本文介绍SpringBoot相关内容。和【跨考菌】一起加油吧~
如果你有收获,记得帮博主一键三连哦😊
1 检索概述
1.1 Elasticsearch概述
我们今天学习的Elasticsearch其实是整合了Lucene框架。
1.2 相关概念
2 Elastic文档学习
学习文档地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
接下来我们根据文档中的介绍,学习elastic的基本用法,首先需要安装elastic:
2.1 安装elastic
拉取镜像:
docker pull elasticsearch:2.4.6 # 这里安装了2.4.6版本,为了和后面的演示项目兼容
查看镜像:
[root@kafka2 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/rabbitmq 3-management 800294d91e31 2 weeks ago 198 MB
jpress latest 773e1fd1b1b9 2 months ago 313 MB
nginx v3 89f9edd3eb63 2 months ago 133 MB
<none> <none> afebc12a7cbe 2 months ago 72.9 MB
docker.io/mysql latest 4f1413420360 2 months ago 545 MB
docker.io/elasticsearch latest 5acf0e8da90b 2 years ago 486 MB
docker.io/elasticsearch 2.4.6 5e9d896dc62c 2 years ago 479 MB
hub.c.163.com/library/tomcat latest 72d2be374029 3 years ago 292 MB
hub.c.163.com/library/nginx latest 46102226f2fd 3 years ago 109 MB
创建docker容器:
[root@kafka2 ~]# docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9201:9200 -p 9301:9300 --restart=always --name ES02 5e9d896dc62c
460013879a8c515953df0bf105782403ec0d7b75bcf9bb6277294968b849a456
开放端口:
[root@kafka2 ~]# firewall-cmd --zone=public --add-port=9201/tcp --permanent
success
[root@kafka2 ~]#
[root@kafka2 ~]# firewall-cmd --zone=public --add-port=9301/tcp --permanent
success
[root@kafka2 ~]# firewall-cmd --reload
访问测试:
2.2 JSON格式化
Elasticsearch 使用 JavaScript Object Notation(或者 JSON)
作为文档的序列化格式。JSON 序列化为大多数编程语言所支持,并且已经成为 NoSQL 领域的标准格式。 它简单、简洁、易于阅读。
下面这个 JSON 文档代表了一个 user 对象:
{
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith",
"info": {
"bio": "Eco-warrior and defender of the weak",
"age": 25,
"interests": [ "dolphins", "whales" ]
},
"join_date": "2014/05/01"
}
2.3 elastic索引
elastic支持rest风格的crud。
PUT:添加数据
DELETE:删除数据
GET:查询数据
下面以员工信息存取为例:
- 每个员工索引一个文档,文档包含该员工的所有信息。
- 每个文档都将是 employee 类型 。
- 该类型位于 索引 megacorp 内。
- 该索引保存在我们的 Elasticsearch 集群中。
2.3.1 PUT存数据
用postman依次存储下面三条数据:
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
PUT /megacorp/employee/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
PUT /megacorp/employee/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}
2.3.2 GET取数据
GET /megacorp/employee/1
返回结果包含了文档的一些元数据,以及 _source 属性,内容是 John Smith 雇员的原始 JSON 文档:
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}
2.3.3 轻量搜索
GET /megacorp/employee/_search # 搜索所有的雇员
可以看到,我们仍然使用索引库 megacorp 以及类型 employee,但与指定一个文档 ID 不同,这次使用 _search 。返回结果包括了所有三个文档,放在数组 hits 中。一个搜索默认返回一条结果。
也可以根据某个字段进行查询:
GET /megacorp/employee/_search?q=last_name:Smith
我们仍然在请求路径中使用 _search 端点,并将查询本身赋值给参数 q= 。返回结果给出了所有的 Smith:
{
...
"hits": {
"total": 2,
"max_score": 0.30685282,
"hits": [
{
...
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},
{
...
"_source": {
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [ "music" ]
}
}
]
}
}
2.3.4 查询表达式
当查询条件比较复杂的时候,可以将查询条件放到json中,作为参数进行查询:
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
更复杂的搜索:
同样搜索姓氏为 Smith 的员工,但这次我们只需要年龄大于 30 的。查询需要稍作调整,使用过滤器 filter ,它支持高效地执行一个结构化查询。
GET /megacorp/employee/_search
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}
2.3.5 全文搜索
搜索下所有喜欢攀岩(rock climbing)的员工:(只要和你的短语相关的都会列举出来)
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
显然我们依旧使用之前的 match 查询在about
属性上搜索 “rock climbing” 。得到两个匹配的文档:
{
...
"hits": {
"total": 2,
"max_score": 0.16273327,
"hits": [
{
...
"_score": 0.16273327,
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},
{
...
"_score": 0.016878016,
"_source": {
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [ "music" ]
}
}
]
}
}
2.3.6 短语搜索
精准匹配一个短语。
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
返回结果仅有 John Smith 的文档。
{
...
"hits": {
"total": 1,
"max_score": 0.23013961,
"hits": [
{
...
"_score": 0.23013961,
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}
]
}
}
3 spring整合elasticsearch
查看springboot整合的包,可以发现有2个elasticsearch的包:
说明springboot有2种方式来和elasticsearch交互:
- Jest(默认不生效):需要导入jest的工具包(io.searchbox.client.JestClient)
- SpringData ElasticSearch【ES版本有可能不合适】
3.1 Jest操作elastic
3.1.1 引入pom依赖
<!-- https://mvnrepository.com/artifact/io.searchbox/jest -->
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
在Jest的自动配置类中可以发现,为我们自动注入了JestClient客户端,方便的进行对elastic的操作。
3.1.2 配置application.properities文件参数
spring.elasticsearch.jest.uris=http://192.168.229.140:9200
Jest是通过http的方式与9200端口进行交互的。
3.1.3 测试
@Autowired
JestClient jestClient;
@Test
public void contextLoads() {
//1、给Es中索引(保存)一个文档;
Article article = new Article();
article.setId(1);
article.setTitle("好消息");
article.setAuthor("zhangsan");
article.setContent("Hello World");
//构建一个索引功能
Index index = new Index.Builder(article).index("atguigu").type("news").build();
try {
//执行
jestClient.execute(index);
} catch (IOException e) {
e.printStackTrace();
}
}
//测试搜索
@Test
public void search() {
//查询表达式
String json = "{\n" +
" \"query\" : {\n" +
" \"match\" : {\n" +
" \"content\" : \"hello\"\n" +
" }\n" +
" }\n" +
"}";
//更多操作:https://github.com/searchbox-io/Jest/tree/master/jest
//构建搜索功能
Search search = new Search.Builder(json).addIndex("atguigu").addType("news").build();
//执行
try {
SearchResult result = jestClient.execute(search);
System.out.println(result.getJsonString());
} catch (IOException e) {
e.printStackTrace();
}
}
说明:在上面的Article
类上可以使用我们的@JestId
注解标注为ID。
public class Article {
@JestId
private Integer id;
private String author;
private String title;
private String content;
3.2 springdata操作elastic
3.2.1 引入pom依赖
<!--SpringBoot默认使用SpringData ElasticSearch模块进行操作-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
3.2.2 配置cluster信息
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=192.168.229.140:9301
这里的端口是刚才虚拟机配置elastic的时候暴露的端口。
3.2.3 编写实体类和对应接口
// 定义了索引和type
@Document(indexName = "atguigu",type = "book")
public class Book {
private Integer id;
private String bookName;
private String author;
xxx
// 泛型的第一个字段是实体类的类型,第二个字段是实体类的主键的类型
public interface BookRepository extends ElasticsearchRepository<Book,Integer> {
}
3.2.4 测试
@Autowired
BookRepository bookRepository;
@Test
public void test02() {
Book book = new Book();
book.setId(1);
book.setBookName("西游记");
book.setAuthor("吴承恩");
bookRepository.index(book); // 存储数据
BookReporitory所有方法:
3.2.5 自定义方法
public interface BookRepository extends ElasticsearchRepository<Book,Integer> {
//参照
// https://docs.spring.io/spring-data/elasticsearch/docs/3.0.6.RELEASE/reference/html/
public List<Book> findByBookNameLike(String bookName);
}
for (Book book : bookRepository.findByBookNameLike("游")) {
System.out.println(book);
}