ElasticSearch安裝
聲明:jdk1.8最低要求 ElasticSearch 用戶端 ,界面工具
下載下傳
官網:www.elastic.co/cn
下載下傳位址:https://www.elastic.co/cn/downloads/elasticsearch#ga-release
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5SYhJjMlNWNjRGOmR2YhZTNjhDM1gjNwYWNhVmN1QDNx8CX2IzLclDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.png)
window下安裝,解壓即可
1.熟悉目錄
- bin 可執行檔案
- config 配置檔案
- log4j2.properties 日志配置檔案
- jvm.options java 虛拟機相關的配置
- elasticsearch.yml elasticsearch 的配置檔案
- lib 相關jar包
- modules 功能子產品
- plugins 插件 ik
2.啟動:通路9200
可視化界面,edge浏覽器插件,elasticSearchvue,安裝即可
kibana安裝
解壓即用
漢化:找到config目錄,将kibana.yml配置檔案最後一行的 en 改為 zh-CN
ES核心概念
elasticSearch 是面向文檔 關系型資料庫和 elasticSearch 客觀的對比
Relational DB | ElasticSearch |
---|---|
資料庫(database) | 索引(indices) |
表(table) | types |
行(rows) | documents |
字段(columns) | flieds |
elasticsearch(叢集)中包含多個索引(資料庫),每個索引中包含多個清單(type),每個清單中包含多個文檔(行),,每個文檔又包含多個字段(列)
實體設計:
elasticsearch在背景把每個索引劃分為多個分片,,每份分片可以在叢集的不同伺服器間遷移
邏輯設計:
一個索引類型包含多個文檔,比如說文檔一,文檔二,當我們找一篇文檔時,可以通過這樣的方式找到它: 索引->類型->文檔ID ,通過這個組合我們就能索引到某個具體的文檔,注意:Id不必是整數,實際上它是個字元串
反向索引:
如果要搜尋含有python 标簽的文章 , 那相對于查找所有原始資料而言,查找反向索引後的資料就會快的多,隻需要檢視标簽這一欄,然後擷取相關的文章id即可,完全過濾掉所有無關的資料,提高效率
IK 分詞器插件
什麼是IK分詞器
分詞,即把一段中文或者其他的語言劃分為一個個關鍵詞,我呢吧在搜尋時會把自己的資訊進行分詞,會把資料庫或者索引庫中的資料進行分詞 , 然後進行一個比對的操作,預設的中文分詞器是把每一個字作為一關鍵詞,這是不符合要求的,我們需要安裝中文分詞器ik來解決這個問題
IK提供了兩個分詞算法: ik_smart 和 ik_max_word,其中ik_smart為最少切分,ik_max_word 為最細粒度劃分
ik下載下傳位址
https://github.com/medcl/elasticsearch-analysis-ik/tags
注意版本對應,以為我現在使用的ES是7.15版本的,而ik 最高隻有7.14,我嘗試下能不能使用
解壓後放在插件目錄裡
然後重新開機觀察
發現失敗了,無法加載插件,啟動不成功,删除的時候記得把插件欄清空,一個目錄也不要留,不然會報錯,安裝插件隻能有一個檔案夾
然後下載下傳了ES7.14.1,成功加載插件
檢視安裝的插件清單
指令
elasticsearch-plugin list
Rest風格說明
一種軟體架構風格,而不是标準,隻是提供了一組設計原則和限制條件,它主要用于用戶端和服務端互動類的軟體
基礎測試
1、使用谷歌插件測試
建立 索引(資料庫)/type(表)/id(行)
檢視
2、類型:
- 字元串類型:text 、keyword
- 數值類型:long,integer,short,byte,double,float,half float,scaled float
- 日期類型:date
- te布爾類型: boolean
- 二進制類型:binary
3、建立規則:
4、獲得這個規則: 可以通過GET請求擷取具體資訊
5、檢視預設的資訊
如果自己的文檔字段沒有指定,那麼es就會給我們預設配置字段類型!_doc是預設的類型
虛心學習,世界上大佬很多,不要認為自己有多優秀,隻是你所在的圈子讓你以為你很優秀
擴充: 通過指令檢視elasticsearch 索引情況,通過get _cat/ 可以獲得es的更多資訊
原始的方法修改
新的方法
删除索引資料
删除索引
關于文檔的基本操作
基本操作
1、添加資料
PUT /dream/user/3 ## 路徑名
{
"name": "龍傲天",
"age": 23,
"desc": "永遠不要驕傲自滿",
"tags": ["肥仔","油膩","直男"]
}
2、擷取資料,查詢
GET /dream/user/1 ## GET 要擷取的資料,根據資料id
GET /dream/_search?q=age:23 # 根據key進行查找,可以帶tpye也可以不帶 q代表query
# 類型為keyword不會分詞
GET /dream/_search?q=name:"沈楚幼" #帶雙引号是精确查詢
GET /dream/_search?q=name:沈楚幼 #不帶雙引号先分詞再查詢
3、更新資料
POST /dream/user/3/_update
{
"name": "修改名字",
"age": "修改年齡"
}
複雜操作搜尋 select(排序,分頁,高亮,模糊查詢,精準查詢)
# 過濾出指定的字段
"_source": ["字段","字段"]
我們之後使用java操作es,所有的方法和對象就是這裡的key
sort排序
"sort": [
{
"字段": {
"order": "desc" # 降序
"order": "asc" # 升序
}
}
],
"from": 0, # 從第0條開始
"size": 1, # 傳回多少條資料
/_search/{current}/{pagesize}
布爾值查詢
must(相當于and):所有的請求都要符合
should(相當于or):滿足一個請求即可
must_not(相當于not):查詢年齡不是23歲的人
過濾filter
- lt:less than 小于
- lte:less than or equal to 小于等于
- gte:greater than or equal to 大于等于
- gt:greater than 大于
精确查詢
term 查詢是直接通過反向索引指定的詞條進行精确的查詢
關于分詞:
term , 直接查詢精确的
match,會使用分詞器解析(先分析文檔,然後再通過分析的文檔進行查詢)
建立規則
PUT /testdb
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"desc": {
"type": "keyword"
}
}
}
}
兩個類型 text 和 keyword
term :代表完全比對,也就是精确查詢,搜尋前不會再對搜尋詞進行分詞解析,直接對關鍵詞進行查找; match :代表模糊比對,搜尋前會對搜尋詞進行分詞解析,然後按分詞比對查找; 一般模糊查找的時候,多用 match ,而精确查找時可以使用 term 。
- term查詢text字段
因為text字段會分詞,而term不分詞,是以term查詢的條件必須是text字段分詞後的某一個。
- 成功
ElasticSearch 的安裝和使用 - 失敗,因為被分詞為了 學 和 無
ElasticSearch 的安裝和使用 -
term查詢keyword字段
term不會分詞。而keyword字段也不分詞。需要完全比對才可以。
- 成功,錯一個字都不行
ElasticSearch 的安裝和使用 - 失敗
ElasticSearch 的安裝和使用 - match查詢text字段
match分詞,text也分詞,隻要match的分詞結果和text的分詞結果有相同的就比對。
- match查詢keyword字段
match會被分詞,而keyword不會被分詞,match的需要跟keyword的完全比對可以。
高亮
自定義高亮
內建SpringBoot
官網文檔:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.14/index.html
1、找原生的依賴
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.1</version>
</dependency>
導入的依賴
<properties>
<java.version>1.8</java.version>
<repackage.classifier/>
<spring-native.version>0.10.3</spring-native.version>
<elasticsearch.version>7.14.1</elasticsearch.version>
</properties>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>${spring-native.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、找對象
3、分析這個類中的方法
配置基本的項目
問題:一定要保證我們導入的依賴和我們自己的es版本一緻
更改版本
進行測試
- 配置
import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * elasticSearch 用戶端配置檔案 * @author YuanZhan * @date 2021/9/24 20:42 */ @Configuration public class ElasticSearchClientConfig { /** * 注入bean,托管給spring,id為restHighLevelClient * @return RestHighLevelClient */ @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost", 9200, "http"))); return client; } }
- 測試
- 建立索引
- 判斷索引是否存在
- 建立文檔
- crud文檔
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mryuan.pojo.User;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.ArrayList;
/**
* es7.14.1 進階用戶端測試API
*/
@SpringBootTest
class Demo01EsApiApplicationTests {
/**
* @Autowired 通過byType 進行裝配,
* 如果有兩個相同類型的bean,需要用用 @Qualifier 指定bean的id
* @Resource 通過byName 進行裝配,全局唯一
*/
@Autowired
private RestHighLevelClient restHighLevelClient;
//測試索引的建立 索引名稱不能包含大寫名稱
@Test
void testCreateIndex() throws IOException {
// 1. 建立索引請求 , 此處導入的是client下的包
CreateIndexRequest request = new CreateIndexRequest("mryuan_index");
// 2. 用戶端執行請求 IndicesClient,請求後獲得響應
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
// 測試擷取索引, 判斷是否存在
@Test
void testGetIndex() throws IOException {
// 1. 擷取索引的請求
GetIndexRequest request = new GetIndexRequest("mryuan_index");
// 2. 判斷是否存在
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
// 測試删除索引
@Test
void testDeleteIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("mryuan_index");
AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
// 是否删除成功
System.out.println(delete.isAcknowledged());
}
// 測試建立文檔
@Test
void testCreateDocument() throws IOException {
User user = new User("張三", 5);
// 擷取索引請求
IndexRequest request = new IndexRequest("mryuan_index");
request.id("1")
.timeout(TimeValue.timeValueSeconds(1))
.timeout("1s");
//将我們的資料放入請求 json writeValueAsString 轉為json字元串
ObjectMapper mapper = new ObjectMapper();
request.source(mapper.writeValueAsString(user), XContentType.JSON);
//用戶端發送請求 ,擷取響應的結果
IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());
System.out.println(indexResponse.status()); // 對應我們指令傳回的狀态 CREATED
}
// 測試文檔擷取 , 判斷是否存在 get /index/_doc/1
@Test
void testIsExist() throws IOException {
// 得到請求
GetRequest request = new GetRequest("mryuan_index", "1");
boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
//擷取文檔的資訊
@Test
void testGetInfo() throws IOException {
// 得到請求
GetRequest request = new GetRequest("mryuan_index", "1");
GetResponse getResponse = restHighLevelClient.get(request, RequestOptions.DEFAULT);
System.out.println(getResponse);
System.out.println(getResponse.getSourceAsString());
System.out.println(getResponse.getSource());
System.out.println(getResponse.getType());
}
//更新文檔資訊
@Test
void testUpdateDoc() throws IOException {
UpdateRequest request = new UpdateRequest("mryuan_index", "1");
User user = new User("MR.yuan", 20);
request.doc(new ObjectMapper().writeValueAsString(user),XContentType.JSON);
UpdateResponse update = restHighLevelClient.update(request, RequestOptions.DEFAULT);
System.out.println(update.status());
}
// 删除文檔資訊
@Test
void testDelDoc() throws IOException{
DeleteRequest request = new DeleteRequest("mryuan_index", "1");
DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
System.out.println(delete.status());
}
// 批量插入資料
@Test
void testBulkRequest() throws IOException {
// Bulk 大部分
BulkRequest request = new BulkRequest();
request.timeout("30s");
ArrayList<User> users = new ArrayList<>();
users.add(new User("yuan1",21));
users.add(new User("yuan2",22));
users.add(new User("yuan3",23));
users.add(new User("yuan4",24));
users.add(new User("yuan5",25));
users.add(new User("yuan6",26));
//批處理請求
for (int i = 0; i < users.size(); i++) {
request.add(new IndexRequest("mryuan_index")
.id(""+i+1) //不設定id 會預設生成随機id
.source(new ObjectMapper().writeValueAsString(users.get(i)),XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
System.out.println(bulk.status()); //狀态
System.out.println(bulk.hasFailures()); // 是否失敗,結果為false代表成功
}
// 查詢
@Test
void testSearch() throws IOException {
SearchRequest request = new SearchRequest("mryuan_index");
//建構搜尋條件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//建構高亮
sourceBuilder.highlighter();
//查詢條件 我們可以使用 QueryBuilders 工具來實作
//QueryBuilders.termQuery 精确查詢
//QueryBuilders.matchAllQuery 查詢所有
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "yuan1");
// MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
sourceBuilder.query(termQueryBuilder);
request.source(sourceBuilder);
SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
System.out.println(new ObjectMapper().writeValueAsString(search.getHits()));
System.out.println("====================================");
for (SearchHit documentFields : search.getHits().getHits()){
System.out.println(documentFields.getSourceAsMap());
}
}
}
實戰
爬蟲
import com.mryuan.pojo.Context;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* @author YuanZhan
* @date 2021/9/25 16:52
*/
@Component
public class HtmlParseUtil {
public List<Context> parseJD(String keywords) throws Exception{
// https://search.jd.com/Search?keyword=java
String url = "https://search.jd.com/Search?keyword="+keywords+"&enc=utf-8";
// 解析網頁 。(Jsoup 傳回的Document 就是浏覽器的Document 對象)
Document document = Jsoup.parse(new URL(url), 30000);
// 可以使用所有的js方法
Element element = document.getElementById("J_goodsList");
Elements elements = element.getElementsByTag("li");
ArrayList<Context> goodsList = new ArrayList<>();
// 擷取元素中的内容,這裡的el 就是每一個li标簽
for (Element el : elements) {
String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
String price = el.getElementsByClass("p-price").eq(0).text();
String name = el.getElementsByClass("p-name").eq(0).text();
if (img!=null&& price!=null && name!=null){
goodsList.add(new Context(name,img,price));
}
}
return goodsList;
}
}
package com.mryuan.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mryuan.pojo.Context;
import com.mryuan.util.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author YuanZhan
* @date 2021/9/25 17:51
*/
@Service
public class ContentService {
@Autowired
private HtmlParseUtil htmlParseUtil;
@Autowired
private RestHighLevelClient restHighLevelClient;
public static void main(String[] args) throws Exception {
new ContentService().parseContext("java");
}
// 1、解析的資料放入 es 索引中
public boolean parseContext(String keywords) throws Exception {
List<Context> list = htmlParseUtil.parseJD(keywords);
BulkRequest bulkRequest = new BulkRequest();
ObjectMapper mapper = new ObjectMapper();
for (int i = 0; i <list.size(); i++) {
bulkRequest.add(new IndexRequest("jd_goodslist")
.id(""+i+1).source(mapper.writeValueAsString(list.get(i)), XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
// 2、擷取這些資料實作搜尋功能
public List<Map<String,Object>> searchPage(String keywords,int pageNo, int pageSize) throws IOException {
if ((pageNo<=1)){
pageNo = 1;
}
//條件搜尋
SearchRequest searchRequest = new SearchRequest("jd_goodslist");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 分頁
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精準比對
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keywords);
sourceBuilder.query(termQueryBuilder);
// 執行搜尋
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析結果
ArrayList<Map<String,Object>> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
list.add(hit.getSourceAsMap());
}
return list;
}
}
@RestController
public class ContentController {
@Autowired
private ContentService contentService;
@GetMapping("/search/{keywords}/{pageNo}/{pageSize}")
public List<Map<String,Object>> search(@PathVariable("keywords") String keywords,
@PathVariable("pageNo") int pageNo,
@PathVariable("pageSize") int pageSize) throws IOException {
return contentService.searchPage(keywords, pageNo, pageSize);
}
}