springboot與檢索(elasticsearch)
一、檢索
Elasticsearch是一個分佈式搜索服務,提供Restful API,底層基於Lucene,採用多shard(分片)的方式保證數據安全,並且提供自動resharding的功能,github等大型的站點也是採用了ElasticSearch作爲其搜索服務,
- 在docker中安裝 啓動elasticsearch 容器
啓動 elasticsearch容器:
# 拉取鏡像
# docker pull elasticsearch:2.4.0
# 啓動 elasticsearch 容器
# docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -di -p 9200:9200 -p 9300:9300 --name es01 elasticsearch:2.4.0
若開啓了防火牆,記得開放 9200 和 9300 端口
查看已經開放的端口
# firewall-cmd --list-ports
開啓端口
# firewall-cmd --zone=public --add-port=80/tcp --permanent
# –zone #作用域
# –add-port=80/tcp #添加端口,格式爲:端口/通訊協議
# –permanent #永久生效,沒有此參數重啓後失效
重啓firewall
# firewall-cmd --reload
啓動容器後:在瀏覽器中輸入 elasticsearch 安裝的容器所在的服務器的 ip:9200
-
elasticsearch 通過restful api 的方式來操作:
將HTTP命令由puT改爲GET可以用來檢索文檔,同樣的,可以使用DELETE命令來刪除文檔,以及使用HEAD指令來檢查文檔是否存在。如果想更新已存在的文檔,只需再次PUT。
例:
PUT ip:9200/megacorp/employee/1
{ "username":"superzheng", "password":"密碼" }
GET ip:9200/megacorp/employee/1
或者搜索:
GET ip:9200/megacorp/employee/_search?q=last_name:Smith
通過json數據體搜索:
POST ip:9200/megacorp/employee/_search
# match 爲模糊匹配 last_name 爲字段 Smith爲匹配值 # 將 match 改爲 match_phrase 爲完全匹配 { "query":{ "match":{ "last_name":"Smith" } } }
通過json數據體高級搜索:
POST ip:9200/megacorp/employee/_search
# 匹配 姓名爲 smith 的並且年齡必須大於 30 的 { "query":{ "bool":{ "must":{ "match":{ "1ast_name":"Smith" } }, "filter":{ "range":{ "age":{"gt":30} } } } }, "highlight":{ "fields":{ "about" : {} } } }
二、在項目中操作 elasticsearch
- 以 jest 的方式操作 elasticsearch
導入 jest 需要的jar 包:
<!-- https://mvnrepository.com/artifact/io.searchbox/jest
以 jest 的方式操作 elasticsearch
-->
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
實體類(用到了 lombok)
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class Article {
/**
* 標識這是主鍵
*/
@JestId
private Long id;
private String author;
private String title;
private String content;
}
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Document(indexName = "mesmile", type = "book") // indexName 索引名 type 類型
public class Book {
private Long id;
private String bookName;
private String author;
}
測試elasticsearch 的存儲與搜索
package cn.mesmile.springboot.elastic;
import cn.mesmile.springboot.elastic.domain.Article;
import cn.mesmile.springboot.elastic.domain.Book;
import cn.mesmile.springboot.elastic.repository.BookRepository;
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
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.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticApplicationTests {
/**
* 對 elasticsearch 進行操作有兩種方式
*
* 方式 ① jest 的方式
* 方式① 需要導入 jar 包
* <!-- https://mvnrepository.com/artifact/io.searchbox/jest
* 以 jest 的方式操作 elasticsearch
* -->
* <dependency>
* <groupId>io.searchbox</groupId>
* <artifactId>jest</artifactId>
* <version>5.3.3</version>
* </dependency>
*
* 方式 ② springdataes 的方式,需要繼承 ElasticsearchRepository<T,D> 接口 T爲實體類,D爲實體類主鍵類型
*
* 注意 springboot 版本 和 elasticsearch 版本 匹配
* 【記得沒錯此依賴只針對的是6.0版本以上ES,6.0版本以下ES不適用於SpringBoot的依賴。】
* 這裏選用的是【 springboot:1.5.9 elasticsearch:2.4.0】
*/
@Autowired
private JestClient jestClient;
@Autowired
private BookRepository bookRepository;
/**
* jest 的方式對 elasticsearch 進行展示
*/
@Test
public void contextLoads() {
Article article = Article.builder()
.id(1L)
.author("superzheng")
.title("通知")
.content("今天項目上線了")
.build();
// 構建一個索引 保存什麼 保存在哪 類型是什麼
Index index = new Index.Builder(article).index("mesmile").type("news").build();
try {
// 執行
// 執行成功後再網址驗證查詢 ip:9200/mesmile/news/1
jestClient.execute(index);
/*
結果如下:
{
"_index": "mesmile",
"_type": "news",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"id": 1,
"author": "superzheng",
"title": "通知",
"content": "今天項目上線了"
}
}
*/
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearch() {
String json = "{\n" +
" \"query\":{\n" +
"\t\t\"match\":{\n" +
"\t\t\t\"content\":\"項目\"\n" +
" }\n" +
" }\n" +
"}";
// 構建搜索
Search search = new Search.Builder(json).addIndex("mesmile").addType("news").build();
try {
// 執行搜索
SearchResult result = jestClient.execute(search);
// 生成 json 字符串
System.out.println(result.getJsonString());
// 搜索並轉換成我們需要的
Article sourceAsObject = result.getSourceAsObject(Article.class,true);
System.out.println(sourceAsObject);
} catch (IOException e) {
e.printStackTrace();
}
/*
{
"took": 58,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5716521,
"hits": [{
"_index": "mesmile",
"_type": "news",
"_id": "1",
"_score": 0.5716521,
"_source": {
"id": 1,
"author": "superzheng",
"title": "通知",
"content": "今天項目上線了"
}
}]
}
}
*/
}
/**
* repository的方式
*/
@Test
public void testBook() {
Book book = Book.builder()
.id(1L)
.bookName("紅樓夢")
.author("曹雪芹")
.build();
// 存儲數據
bookRepository.index(book);
}
@Test
public void testSearchLike() {
// 模糊查詢
List<Book> data = bookRepository.findByBookNameLike("樓");
data.forEach(System.out::println);
}
}
三、出現異常
NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{BCBUirWrTIy-RJ5ZnNj3xA}{40.100.00.200}{40.100.00.200:9300}]
]
<!-- springboot data elasticsearch 支持
【記得沒錯此依賴只針對的是6.0版本以上ES,6.0版本以下ES不適用於SpringBoot的依賴。】
這裏選用的是【 springboot:1.5.9 elasticsearch:2.4.0】
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
項目配置文件
# 9200作爲Http協議,主要用於外部通訊
#9300作爲Tcp協議,jar之間就是通過tcp協議通訊
#ES集羣之間是通過9300進行通訊
#9200 是ES節點與外部通訊使用的端口。它是http協議的RESTful接口(各種CRUD操作都是走的該端口,如查詢:http://localhost:9200/user/_search)。
#9300是ES節點之間通訊使用的端口。它是tcp通訊端口,集羣間和TCPclient都走的它。(java程序中使用ES時,在配置文件中要配置該端口)
spring:
elasticsearch:
jest:
uris: http://40.100.00.200:9200
data:
elasticsearch:
cluster-nodes: 40.100.00.200:9300
# 默認名稱是 elasticsearch 通過 ip:9200 查看
cluster-name: elasticsearch