Elasticsearch分布式引擎7.x,2021黑马详细课程笔记
文章目錄
- 一、ES的一些概念
- 1.1索引和映射
- ELS與Mysql的對比
- 2.創建索引庫:
- 2.1mapping映射屬性
- 2.2索引庫的CRUD
- 2.2.1創建索引庫和映射
- 2.2.2查詢數據庫:
- 2.2.3修改索引庫,添加新字段
- 2.2.4.刪除索引庫
- 2.2.5總結
- 3.文檔操作
- 3.1.新增文檔
- 查詢文檔
- 3.3刪除文檔
- 3.4修改文檔
- 3.4.2只修改Id匹配的文檔中的部分字段
- 3.5總結
- 4 RestAPI--javaClient的操作文檔
- 4.0.1導入工程和數據
- 4.0.2導入項目、
- 4.03mapping映射分析
- 4.0.4初始化RestClient
- 4.1創建索引庫
- 4.1.2完整示例
- 4.2刪除索引庫
- 4.3判斷索引庫是否存在
- 4.4.總結
- 5.RestClient文檔
- 5.1新增文檔
- 5.1.2語法說明
- 5.1.3完整新增代碼
- 5.2查詢文檔
- 5.2.2完整代碼
- 5.4修改文檔
- 5.5批量導入文檔
- 6.操作文檔的源碼
一、ES的一些概念
elasticsearch是面向**文檔(Document)**存儲的,可以是數據庫中的一條商品數據,一個訂單信息。文檔數據會被序列化為json格式后存儲在elasticsearch中:
- 而json中的字段類(Field)似于數據庫的列。
1.1索引和映射
索引(index),就是相同類型的文檔的集合
因此,我們可以把索引當做是數據庫中的表。
數據庫的表會有約束信息,用來定義表的結構、字段的名稱、類型等信息。因此,索引庫中就有映射(mapping),是索引中文檔的字段約束信息,類似表的結構約束。
ELS與Mysql的對比
- 測試分詞器
其中analyzer代表分詞,選項有"ik_smart";“ik_max_word”
- 測試分詞器的拓展,這個需要在其中的data文件中進行分詞的設置
2.創建索引庫:
2.1mapping映射屬性
mapping是對索引庫中文檔的約束,常見的mapping屬性包括:
- type:字段數據類型,常見的簡單類型有:
- 字符串:text(可分詞的文本)、keyword(精確值,例如:品牌、國家、ip地址)
- 數值:long、integer、short、byte、double、float、
- 布爾:boolean
- 日期:date
- 對象:object
- index:是否創建索引,默認為true
- analyzer:使用哪種分詞器
- properties:該字段的子字段
2.2索引庫的CRUD
這里使用Kibana編寫DSL的方式來演示。
2.2.1創建索引庫和映射
基本語法:
- 請求方式:PUT
- 請求路徑:/索引庫名,可以自定義
- 請求參數:mapping映射
格式:
- 示例:
2.2.2查詢數據庫:
基本語法**:
-
請求方式:GET
-
請求路徑:/索引庫名
-
請求參數:無
2.2.3修改索引庫,添加新字段
倒排索引結構雖然不復雜,但是一旦數據結構改變(比如改變了分詞器),就需要重新創建倒排索引,這簡直是災難。因此索引庫一旦創建,無法修改mapping。
2.2.4.刪除索引庫
語法:**
-
請求方式:DELETE
-
請求路徑:/索引庫名
-
請求參數:無
**格式:
DELETE /索引庫 # 修改索引庫,添加新字段 PUT /heima/_mapping {"properties":{"age":{"type":"integer"}} }2.2.5總結
索引庫操作有哪些?
- 創建索引庫:PUT /索引庫名
- 查詢索引庫:GET /索引庫名
- 刪除索引庫:DELETE /索引庫名
- 修改字段:PUT /索引庫名/_mapping
3.文檔操作
3.1.新增文檔
語法:
POST /索引庫名/_doc/文檔id {"字段1": "值1","字段2": "值2","字段3": {"子屬性1": "值3","子屬性2": "值4"},// ... }示例:
POST /heima/_doc/1 {"info":"黑馬程序元學java","email":"645299910@qq.com","name":{"firstName":"云","lastName":"趙"} }響應:
查詢文檔
GET /heima/_doc/13.3刪除文檔
刪除使用DELETE請求,同樣,需要根據id進行刪除
語法:
3.4修改文檔
語法:
3.4.2只修改Id匹配的文檔中的部分字段
POST /heima/_update/1 {"doc": {"email": "ZhaoYun@itcast.cn"} }3.5總結
文檔操作有哪些?
- 創建文檔:post /索引/_doc/id
- 查詢文檔:GET/SUOYIN/_doc/id
- 修改文檔:put/suoyin/_doc/id
- 刪除文檔:delete/suoyin/_doc/id
4 RestAPI–javaClient的操作文檔
學習的是JAVA HighLevel Rest Client客戶端API
4.0.1導入工程和數據
1.先導入課程的sql
CREATE TABLE `tb_hotel` (`id` bigint(20) NOT NULL COMMENT '酒店id',`name` varchar(255) NOT NULL COMMENT '酒店名稱;例:7天酒店',`address` varchar(255) NOT NULL COMMENT '酒店地址;例:航頭路',`price` int(10) NOT NULL COMMENT '酒店價格;例:329',`score` int(2) NOT NULL COMMENT '酒店評分;例:45,就是4.5分',`brand` varchar(32) NOT NULL COMMENT '酒店品牌;例:如家',`city` varchar(32) NOT NULL COMMENT '所在城市;例:上海',`star_name` varchar(16) DEFAULT NULL COMMENT '酒店星級,從低到高分別是:1星到5星,1鉆到5鉆',`business` varchar(255) DEFAULT NULL COMMENT '商圈;例:虹橋',`latitude` varchar(32) NOT NULL COMMENT '緯度;例:31.2497',`longitude` varchar(32) NOT NULL COMMENT '經度;例:120.3925',`pic` varchar(255) DEFAULT NULL COMMENT '酒店圖片;例:/img/1.jpg',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;4.0.2導入項目、
- application.yml
- 注意這里我用的mysql5.7如果是8,需要加上時區
4.03mapping映射分析
創建索引庫,最關鍵的是mapping映射,而mapping映射要考慮的信息包括:
- 字段名
- 字段數據類型
- 是否參與搜索
- 是否需要分詞
- 如果分詞,分詞器是什么?
其中:
- 字段名、字段數據類型,可以參考數據表結構的名稱和類型
- 是否參與搜索要分析業務來判斷,例如圖片地址,就無需參與搜索
- 是否分詞呢要看內容,內容如果是一個整體就無需分詞,反之則要分詞
- 分詞器,我們可以統一使用ik_max_word
來看下酒店數據的索引庫結構:
這里有一個重點,對于經緯度,我們采用的是location,type是geo_point
PUT /hotel {"mappings": {"properties": {"id": {"type": "keyword"},"name":{"type": "text","analyzer": "ik_max_word","copy_to": "all"},"address":{"type": "keyword","index": false},"price":{"type": "integer"},"score":{"type": "integer"},"brand":{"type": "keyword","copy_to": "all"},"city":{"type": "keyword","copy_to": "all"},"starName":{"type": "keyword"},"business":{"type": "keyword"},"location":{"type": "geo_point"},"pic":{"type": "keyword","index": false},"all":{"type": "text","analyzer": "ik_max_word"}}} }幾個特殊字段說明:
- location:地理坐標,里面包含精度、緯度
- all:一個組合字段,其目的是將多字段的值 利用copy_to合并,提供給用戶搜索
4.0.4初始化RestClient
在elasticsearch提供的API中,與elasticsearch一切交互都封裝在一個名為RestHighLevelClient的類中,必須先完成這個對象的初始化,建立與elasticsearch的連接。
分為三步:
1)引入es的RestHighLevelClient依賴:
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>2)因為SpringBoot默認的ES版本是7.6.2,所以我們需要覆蓋默認的ES版本:
<properties><java.version>1.8</java.version><elasticsearch.version>7.12.1</elasticsearch.version> </properties>3)初始化RestHighLevelClient:
初始化的代碼如下:
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.117.129:9200") ));這里為了單元測試方便,我們創建一個測試類HotelIndexTest,然后將初始化的代碼編寫在@BeforeEach方法中:
package cn.itcast.hotel;import org.apache.http.HttpHost; import org.elasticsearch.client.RestHighLevelClient; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test;import java.io.IOException;public class HotelIndexTest {private RestHighLevelClient client;@BeforeEachvoid setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.150.101:9200")));}@AfterEachvoid tearDown() throws IOException {this.client.close();} }4.1創建索引庫
代碼分為三步:
- 1)創建Request對象。因為是創建索引庫的操作,因此Request是CreateIndexRequest。
- 2)添加請求參數,其實就是DSL的JSON參數部分。因為json字符串很長,這里是定義了靜態字符串常量MAPPING_TEMPLATE,讓代碼看起來更加優雅。
- 3)發送請求,client.indices()方法的返回值是IndicesClient類型,封裝了所有與索引庫操作有關的方法。
4.1.2完整示例
在hotel-demo的cn.itcast.hotel.constants包下,創建一個類,定義mapping映射的JSON字符串常量:
package cn.itcast.hotel.constants;public class HotelConstants {public static final String MAPPING_TEMPLATE = "{\n" +" \"mappings\": {\n" +" \"properties\": {\n" +" \"id\": {\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"name\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"address\":{\n" +" \"type\": \"keyword\",\n" +" \"index\": false\n" +" },\n" +" \"price\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"score\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"brand\":{\n" +" \"type\": \"keyword\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"city\":{\n" +" \"type\": \"keyword\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"starName\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"business\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"location\":{\n" +" \"type\": \"geo_point\"\n" +" },\n" +" \"pic\":{\n" +" \"type\": \"keyword\",\n" +" \"index\": false\n" +" },\n" +" \"all\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\"\n" +" }\n" +" }\n" +" }\n" +"}"; }- 在hotel-demo中的HotelIndexTest測試類中,編寫單元測試,實現創建索引:
4.2刪除索引庫
與創建索引庫相比:
- 請求方式從PUT變為DELTE
- 請求路徑不變
- 無請求參數
所以代碼的差異,注意體現在Request對象上。依然是三步走:
- 1)創建Request對象。這次是DeleteIndexRequest對象
- 2)準備參數。這里是無參
- 3)發送請求。改用delete方法
在hotel-demo中的HotelIndexTest測試類中,編寫單元測試,實現刪除索引:
@Test void testDeleteHotelIndex() throws IOException {// 1.創建Request對象DeleteIndexRequest request = new DeleteIndexRequest("hotel");// 2.發送請求client.indices().delete(request, RequestOptions.DEFAULT); }4.3判斷索引庫是否存在
因此與刪除的Java代碼流程是類似的。依然是三步走:
- 1)創建Request對象。這次是GetIndexRequest對象
- 2)準備參數。這里是無參
- 3)發送請求。改用exists方法
4.4.總結
JavaRestClient操作elasticsearch的流程基本類似。核心是client.indices()方法來獲取索引庫的操作對象。
索引庫操作的基本步驟:
- 初始化RestHighLevelClient
- 創建XxxIndexRequest。XXX是Create、Get、Delete
- 準備DSL( Create時需要,其它是無參)
- 發送請求。調用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete
5.RestClient文檔
- 這里啟動類,黑馬老師有個bug
為了與索引庫操作分離,我們再次參加一個測試類,做兩件事情:
- 初始化RestHighLevelClient
- 我們的酒店數據在數據庫,需要利用IHotelService去查詢,所以注入這個接口
5.1新增文檔
索引庫實體類:
@Data @TableName("tb_hotel") public class Hotel {@TableId(type = IdType.INPUT) //主鍵private Long id;private String name;private String address;private Integer price;private Integer score;private String brand;private String city;private String starName;private String business;private String longitude;private String latitude;private String pic; }與我們的索引庫結構存在差異:
- longitude和latitude需要合并為location
因此,我們需要定義一個新的類型,與索引庫結構吻合:
其實也可以說是DTO類
5.1.2語法說明
新增文檔的DSL語句如下
POST /{索引庫名}/_doc/1 {"name": "Jack","age": 21 }
可以看到與創建索引庫類似,同樣是三步走:
- 1)創建Request對象
- 2)準備請求參數,也就是DSL中的JSON文檔
- 3)發送請求
變化的地方在于,這里直接使用client.xxx()的API,不再需要client.indices()了。
5.1.3完整新增代碼
我們導入酒店數據,基本流程一致,但是需要考慮幾點變化:
- 酒店數據來自于數據庫,我們需要先查詢出來,得到hotel對象
- hotel對象需要轉為HotelDoc對象
- HotelDoc需要序列化為json格式
因此,代碼整體步驟如下:
- 1)根據id查詢酒店數據Hotel
- 2)將Hotel封裝為HotelDoc
- 3)將HotelDoc序列化為JSON
- 4)創建IndexRequest,指定索引庫名和id
- 5)準備請求參數,也就是JSON文檔
- 6)發送請求
在hotel-demo的HotelDocumentTest測試類中,編寫單元測試:
@Test void testAddDocument() throws IOException {// 1.根據id查詢酒店數據Hotel hotel = hotelService.getById(61083L);// 2.轉換為文檔類型HotelDoc hotelDoc = new HotelDoc(hotel);// 3.將HotelDoc轉jsonString json = JSON.toJSONString(hotelDoc);// 1.準備Request對象IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());// 2.準備Json文檔request.source(json, XContentType.JSON);// 3.發送請求client.index(request, RequestOptions.DEFAULT); }5.2查詢文檔
可以看到,結果是一個JSON,其中文檔放在一個`_source`屬性中,因此解析就是拿到`_source`,反序列化為Java對象即可。與之前類似,也是三步走:- 1)準備Request對象。這次是查詢,所以是GetRequest - 2)發送請求,得到結果。因為是查詢,這里調用client.get()方法 - 3)解析結果,就是對JSON做反序列化5.2.2完整代碼
在hotel-demo的HootelDocument測試類中,編寫單元測試
@Test void testGetDocumentById() throws IOException {// 1.準備RequestGetRequest request = new GetRequest("hotel", "61082");// 2.發送請求,得到響應GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.解析響應結果String json = response.getSourceAsString();HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);System.out.println(hotelDoc); }5.4修改文檔
修改我們講過兩種方式:
- 全量修改:本質是先根據id刪除,再新增
- 增量修改:修改文檔中的指定字段值
在RestClient的API中,全量修改與新增的API完全一致,判斷依據是ID:
- 如果新增時,ID已經存在,則修改
- 如果新增時,ID不存在,則新增
這里不再贅述,我們主要關注增量修改。
代碼示例如圖:
與之前類似,也是三步走:
- 1)準備Request對象。這次是修改,所以是UpdateRequest
- 2)準備參數。也就是JSON文檔,里面包含要修改的字段
- 3)更新文檔。這里調用client.update()方法
5.5批量導入文檔
案例需求:利用BulkRequest批量將數據庫數據導入到索引庫中。
步驟如下:
-
利用mybatis-plus查詢酒店數據
-
將查詢到的酒店數據(Hotel)轉換為文檔類型數據(HotelDoc)
-
利用JavaRestClient中的BulkRequest批處理,實現批量新增文檔
-
可以看到,能添加的請求包括: -
IndexRequest,也就是新增
-
UpdateRequest,也就是修改
-
DeleteRequest,也就是刪除
因此Bulk中添加了多個IndexRequest,就是批量新增功能了。示例
其實還是三步走:
- 1)創建Request對象。這里是BulkRequest
- 2)準備參數。批處理的參數,就是其它Request對象,這里就是多個IndexRequest
- 3)發起請求。這里是批處理,調用的方法為client.bulk()方法
我們在導入酒店數據時,將上述代碼改造成for循環處理即可。
@Test void testBulkRequest() throws IOException {// 批量查詢酒店數據List<Hotel> hotels = hotelService.list();// 1.創建RequestBulkRequest request = new BulkRequest();// 2.準備參數,添加多個新增的Requestfor (Hotel hotel : hotels) {// 2.1.轉換為文檔類型HotelDocHotelDoc hotelDoc = new HotelDoc(hotel);// 2.2.創建新增文檔的Request對象request.add(new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc), XContentType.JSON));}// 3.發送請求client.bulk(request, RequestOptions.DEFAULT); }6.操作文檔的源碼
package cn.itcast.hotel;import cn.itcast.hotel.pojo.Hotel; import cn.itcast.hotel.pojo.HotelDoc; import cn.itcast.hotel.service.IHotelService;import com.alibaba.fastjson.JSON; import org.apache.http.HttpHost; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; 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.List;@SpringBootTest public class HotelDocumentTest {private RestHighLevelClient client;@Autowiredprivate IHotelService hotelService;/*** 新增文檔操作* 查詢酒店:需要注意啟動類處mapperscan老師錯了,要加上pojo* application。yml中的mysql的url改成自己的* @throws IOException*/@Testvoid testDocument() throws IOException {//根據id查詢酒店數據Hotel hotel = hotelService.getById(61083L);//轉換為文檔類型HotelDoc hotelDoc = new HotelDoc(hotel);//1.準備request對象IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());//2.準備json對象request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);client.index(request, RequestOptions.DEFAULT);}/*** 查詢文檔信息* @throws IOException*/@Testvoid testGetDocument() throws IOException {//1.準備requestGetRequest request = new GetRequest("hotel","61083");//2.準備得到response對象GetResponse response = client.get(request, RequestOptions.DEFAULT);//3.解析響應結果String json = response.getSourceAsString();HotelDoc doc = JSON.parseObject(json, HotelDoc.class);System.out.println(doc);}/*** 文檔修改* @throws IOException*/@Testvoid updateDocument() throws IOException {//1.準備requestUpdateRequest request = new UpdateRequest("hotel", "61083");request.doc("price","900");//準備更新操作client.update(request, RequestOptions.DEFAULT);}/**** 文檔刪除* @throws IOException*/@Testvoid deleteDocument() throws IOException {DeleteRequest request = new DeleteRequest("hotel", "61083");client.delete(request,RequestOptions.DEFAULT);}@Testvoid testListDocument() throws IOException {List<Hotel> hotels = hotelService.list();//批處理獲得到的requestBulkRequest request = new BulkRequest();for (Hotel hotel : hotels) {//將hotel變成文檔HotelDoc hotelDoc = new HotelDoc(hotel);request.add(new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc),XContentType.JSON));}//調用批處理client.bulk(request,RequestOptions.DEFAULT);}//初始化@BeforeEachvoid setUp(){this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.117.129:9200")));}@AfterEachvoid tearDown() throws IOException {this.client.close();}}總結
以上是生活随笔為你收集整理的Elasticsearch分布式引擎7.x,2021黑马详细课程笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 测试web网站速度
- 下一篇: 沈颖刚:生物柴油或是高原柴油货车污染治理