1.检索
Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了Elasticsearch作为其搜索服务。
2.概念
以员工信息存储为例,一个文档代表一个员工数据。存储到ElasticSearch的行为叫索引,在索引文档之前,需要确定文档存储的位置。一个ElasticSearch集群可以包含多个索引,每个索引可以包含多个类型,不同类型存储多个文档,每个文档有多个属性。
3.整合ElasticSearch测试
1.安装镜像
使用命令:docker pull elasticsearch:7.6.2下载镜像,不带tag会提示lastest找不到,所以就指定一个tag。
使用命令:docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 elasticsearch:7.6.2启动镜像。这里需要说一下,ElasticSearch启动,默认吃2G的内存,内存不够的可以带上-e参数加上内存限制。如果内存足够,可以不带-e参数,这里有两个-p,9200端口是web通信端口,9300是分布式ElasticSearch结点间通信端口。
启动之后,访问http://192.168.0.123:9200/,如果可以访问到,说明启动成功了,如果访问不到,说明启动失败了。
这里,我启动失败了,使用命令docker logs 容器id,查看报错信息,一共有两个。
ERROR: [2] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
[2]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
ERROR: Elasticsearch did not exit normally - check the logs at /usr/share/elasticsearch/logs/docker-cluster.log
第一个报错的意思是ElasticSearch拥有的内存太小,至少需要262144。使用命令sysctl -a|grep vm.max_map_count查看得到vm.max_map_count = 65530,我们需要修改这个值。单次生效的方法:sysctl -w vm.max_map_count=262144。要想永久生效,需要在/etc/sysctl.conf文件下添加一行:vm.max_map_count=262144并重启,即可解决。
第二个问题应该是高版本和低版本的不同,修改启动命令为:docker run -d -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:7.6.2,这里多了一个-e "discovery.type=single-node"参数,应该是以单结点方式启动的意思,避免集群检查。
再次访问http://192.168.0.123:9200/,可以看到信息,表示ElasticSearch启动成功。
2.功能测试
ElasticSearch中文文档地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html。
Elasticsearch是面向文档的,意味着它存储整个对象或文档。Elasticsearch不仅存储文档,而且索引每个文档的内容,使之可以被检索。在Elasticsearch中,我们对文档进行索引、检索、排序和过滤—而不是对行列数据。这是一种完全不同的思考数据的方式,也是Elasticsearch能支持复杂全文检索的原因。
ElasticSearch使用JSON作为文档的序列化格式。
向ES中添加员工信息:
发送PUT请求到http://192.168.0.123:9200/megacorp/employee/1,携带的请求体是JSON格式的,url中的megacorp是索引名称,employee是类型名称,1是员工id。这里使用Postman来发送这个请求。
从ES中获取员工信息:
发送GET请求到http://192.168.0.123:9200/megacorp/employee/1即可拿到数据。
从ES中删除员工信息:
发送DELETE请求到http://192.168.0.123:9200/megacorp/employee/1即可删除数据。
查看ES中是否有员工信息:
发送HEAD请求到http://192.168.0.123:9200/megacorp/employee/1,如果返回200,表示有这个员工信息,如果返回404,表示没有这个员工信息。
修改ES中员工信息:
和新增一样,发送PUT请求即可。
查询全部信息:
发送GET请求到http://192.168.0.123:9200/megacorp/employee/_search即可。
按照条件查询:
比如,按照last_name属性查询,需要将q=last_name:Smith参数带到请求后面即可,发送GET请求到http://192.168.0.123:9200/megacorp/employee/_search?q=last_name:Smith。
按照检索表达式查询:
更复杂的检索表达式:
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}
全文检索表达式:
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
短语检索表达式:
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
高亮检索表达式:
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
3.Spring Boot整合ElasticSearch
新建Spring Boot项目,添加Spring Web、Spring Data ElasticSearch(Access+Driver)依赖。
Spring Boot默认支持两种技术和ES交互:Jest(现在已经@Deprecated了)和SpringData ElasticSearch。
SpringData ElasticSearch的自动配置类中会导入Client、ElasticSearchTemplate,还提供了ElasticSearchRepository的子接口操作ES。
加入yml配置文件。
spring:
data:
elasticsearch:
# cluster-name的取值,要和浏览器访问192.168.0.123:9200的返回结果里的cluster-name一致
cluster-name: docker-cluster
cluster-nodes: 192.168.0.123:9300
观察左侧导入的org.elasticsearch:elasticsearch:6.8.7,这个6.8.7是spring-boot-starter-data-elasticsearch帮我们导入的,而我们镜像里的版本是7.6.2,ElasticSearch对版本要求比较严格,这里的版本不一致,后面会报错,所以需要将镜像换成6.8.7版本。
Spring Data ElasticSearch对应的ElasticSearch版本查询地址:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.0.RC3/reference/html/#preface.versions
Spring Data Elasticsearch导入的Elasticsearch versions
Spring Data ElasticSearch | ElasticSearch |
3.2.x | 6.8.1 |
3.1.x | 6.2.2 |
3.0.x | 5.5.0 |
2.1.x | 2.4.0 |
2.0.x | 2.2.0 |
1.3.x | 1.5.2 |
回到虚拟机中,替换Docker镜像版本。
- 使用命令docker stop 容器id,停止容器。
- 使用命令docker rm 容器id,删除容器。
- 使用命令docker images查看所有镜像,后使用docker rmi 镜像id,删除ElasticSearch的镜像。
- 使用命令docker pull elasticsearch:6.8.7下载6.8.7版本的ElasticSearch镜像。
- 使用命令docker run -d -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:6.8.7创建并启动容器。
- 通过浏览器访问http://192.168.0.123:9200地址,确认版本号是不是6.8.7,以及容器是否正常启动。
创建bean以及repository,通过测试类进行测试。
package com.atguigu.elasticsearch.bean;
import org.springframework.data.elasticsearch.annotations.Document;
// indexName:索引名称 type:索引类型
@Document(indexName = "atguigu", type = "book")
public class Book {
private int id;
private String name;
private String author;
public Book() {
}
public Book(int id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}
package com.atguigu.elasticsearch.repository;
import com.atguigu.elasticsearch.bean.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface BookRepository extends ElasticsearchRepository<Book, Integer> {
public List<Book> findByNameLike(String name);
public List<Book> findByAuthorLike(String author);
}
package com.atguigu.elasticsearch;
import com.atguigu.elasticsearch.bean.Book;
import com.atguigu.elasticsearch.repository.BookRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class SpringBootElasticsearch03ApplicationTests {
@Autowired
BookRepository bookRepository;
@Test
void contextLoads() {
}
@Test
public void index() {
Book book = new Book();
book.setId(1);
book.setName("西游记");
book.setAuthor("吴承恩");
bookRepository.index(book);
}
@Test
public void findByNameLike() {
List<Book> bookList = bookRepository.findByNameLike("西");
for (Book book : bookList) {
System.out.println(book);
}
}
@Test
public void findByAuthorLike() {
List<Book> bookList = bookRepository.findByAuthorLike("吴");
for (Book book : bookList) {
System.out.println(book);
}
}
}
运行index()方法,通过浏览器访问http://192.168.0.123:9200/atguigu/book/_search可以查看到全部索引数据,访问http://192.168.0.123:9200/atguigu/book/1可以看到刚才插入的id为1的索引数据。调用findByNameLike()方法可以以Like书名的方式查询到结果,但是我们只写了一个接口,并没有写实现,是如何实现的呢?
其实是根据方法名,构造查询表达式交给ES查询。上面的例子是按照name域模糊查询,所以方法名是findByNameLike(),如果要模糊查询author域,则方法名必须是findByAuthorLike(),字母大小写也不能错,否则,就会报错,或者查询结果不符合预期。
方法名和查询表达式的对应关系,参照这个地址了解一下:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.7.RELEASE/reference/html/#elasticsearch.repositories。
另外,还支持@Query注解的方式标注Query表达式,标注在接口上,有点类似于Mybatis的注解形式。
另外,还有ElasticSearchTemplate的查询,可以构造更复杂的查询方式。