分布式搜索引擎Elasticsearch講解專題(二)
??今天主要介紹索引庫和文檔的相關(guān)Rest操作,使用PostMan或者Kibbna來進(jìn)行相關(guān)請求接口的調(diào)用,實現(xiàn)索引庫的創(chuàng)建和維護(hù),文檔的添加和維護(hù)等。以及使用ES提供的API實現(xiàn)索引庫和文檔的CRUD操作。
3.索引庫操作
索引庫就類似數(shù)據(jù)庫表,mAPPing映射就類似表的結(jié)構(gòu)。
我們要向es中存儲數(shù)據(jù),必須先創(chuàng)建“庫”和“表”。
3.1.mAPPing映射屬性
mAPPing是對索引庫中文檔的約束,常見的mAPPing屬性包括:
type:字段數(shù)據(jù)類型,常見的簡單類型有:
字符串:text(可分詞的文本)、keyword(精確值,例如:品牌、國家、ip地址)
數(shù)值:long、integer、short、byte、double、float、
布爾:boolean
日期:date
對象:object
index:是否創(chuàng)建索引,默認(rèn)為true,index=true表示均可以參與搜索
analyzer:使用哪種分詞器
properties:該字段的子字段
例如下面的json文檔:
對應(yīng)的每個字段映射(mAPPing):
age:類型為 integer;參與搜索,因此需要index為true;無需分詞器
weight:類型為float;參與搜索,因此需要index為true;無需分詞器
isMarried:類型為boolean;參與搜索,因此需要index為true;無需分詞器
info:類型為字符串,需要分詞,因此是text;參與搜索,因此需要index為true;分詞器可以用ik_smart
email:類型為字符串,但是不需要分詞,因此是keyword;不參與搜索,因此需要index為false;無需分詞器
score:雖然是數(shù)組,但是我們只看元素的類型,類型為float;參與搜索,因此需要index為true;無需分詞器
name:類型為object,需要定義多個子屬性
name.firstName;類型為字符串,但是不需要分詞,因此是keyword;參與搜索,因此需要index為true;無需分詞器
name.lastName;類型為字符串,但是不需要分詞,因此是keyword;參與搜索,因此需要index為true;無需分詞器
3.2.索引庫的CRUD
這里我們統(tǒng)一使用Kibana編寫DSL的方式來演示。
3.2.1.創(chuàng)建索引庫和映射
基本語法:
請求方式:PUT
請求路徑:/索引庫名,可以自定義
請求參數(shù):mAPPing映射
格式:
示例:
2.2.2.查詢索引庫
基本語法:
請求方式:GET
請求路徑:/索引庫名
請求參數(shù):無
格式:
?GET /索引庫名
2.2.3.修改索引庫
倒排索引結(jié)構(gòu)雖然不復(fù)雜,但是一旦數(shù)據(jù)結(jié)構(gòu)改變(比如改變了分詞器),就需要重新創(chuàng)建倒排索引,這簡直是災(zāi)難。因此索引庫一旦創(chuàng)建,無法修改mAPPing。
雖然無法修改mAPPing中已有的字段,但是卻允許添加新的字段到mAPPing中,因為不會對倒排索引產(chǎn)生影響。
語法說明:?
2.2.4.刪除索引庫
語法:
請求方式:DELETE
請求路徑:/索引庫名
請求參數(shù):無
格式:
?DELETE /索引庫名
2.2.5.總結(jié)
索引庫操作有哪些?
創(chuàng)建索引庫:PUT /索引庫名
查詢索引庫:GET /索引庫名
刪除索引庫:DELETE /索引庫名
添加字段:PUT /索引庫名/_mAPPing
4.文檔操作
4.1.新增文檔
語法:
示例:
4.2.查詢文檔
根據(jù)rest風(fēng)格,新增是post,查詢應(yīng)該是get,不過查詢一般都需要條件,這里我們把文檔id帶上。
語法:
?GET /{索引庫名稱}/_doc/{id}
通過kibana查看數(shù)據(jù):
?GET /znz/_doc/1
#查詢所有文檔
GET /znz/_search
4.3.刪除文檔
刪除使用DELETE請求,同樣,需要根據(jù)id進(jìn)行刪除:
語法:
?DELETE /{索引庫名}/_doc/id值
示例:
?# 根據(jù)id刪除數(shù)據(jù) ?DELETE /znz/_doc/1
4.4.修改文檔
修改有兩種方式:
全量修改:直接覆蓋原來的文檔
增量修改:修改文檔中的部分字段
4.4.1.全量修改
全量修改是覆蓋原來的文檔,其本質(zhì)是:
根據(jù)指定的id刪除文檔
新增一個相同id的文檔
注意:如果根據(jù)id刪除時,id不存在,第二步的新增也會執(zhí)行,也就從修改變成了新增操作了。
語法:
示例:
?
4.4.2.增量修改
增量修改是只修改指定id匹配的文檔中的部分字段。
語法:
?
示例:
4.5.總結(jié)
文檔操作有哪些?
創(chuàng)建文檔:POST /{索引庫名}/_doc/文檔id { json文檔 }
查詢文檔:GET /{索引庫名}/_doc/文檔id
刪除文檔:DELETE /{索引庫名}/_doc/文檔id
修改文檔:
全量修改:PUT /{索引庫名}/_doc/文檔id { json文檔 }
增量修改:POST /{索引庫名}/_update/文檔id { "doc": {字段}}
5.使用API來操作索引庫和文檔
5.1 創(chuàng)建表結(jié)構(gòu)
5.2 操作索引庫
5.2.1? 定義其對應(yīng)的MAPPing映射
為方便引用,我們定義一個常量來存儲分析設(shè)計的映射結(jié)構(gòu):
幾個特殊字段說明:
location:地理坐標(biāo),里面包含精度、緯度
all:一個組合字段,其目的是將多字段的值 利用copy_to合并,提供給用戶搜索.其值在查詢時不顯示。
地理坐標(biāo)說明:

copy_to說明:copy_to指向的字段字段類型要為:text。

?5.2.2? 初始化RestClient
在elasticsearch提供的API中,與elasticsearch一切交互都封裝在一個名為RestHighLevelClient的類中,必須先完成這個對象的初始化,建立與elasticsearch的連接。
分為三步:
1)引入es的RestHighLevelClient依賴:
2)因為SpringBoot默認(rèn)的ES版本是7.6.2,所以我們需要覆蓋默認(rèn)的ES版本:
3)初始化RestHighLevelClient:
初始化的代碼如下:
這里為了單元測試方便,我們創(chuàng)建一個測試類HotelIndexTest,然后將初始化的代碼編寫在@Before方法中:
5.2.3 創(chuàng)建索引庫
代碼分為三步:
1)創(chuàng)建Request對象。因為是創(chuàng)建索引庫的操作,因此Request是CreateIndexRequest。
2)添加請求參數(shù),其實就是DSL的JSON參數(shù)部分。因為json字符串很長,這里是定義了靜態(tài)字符串常量MAPPING_TEMPLATE,讓代碼看起來更加優(yōu)雅。
3)發(fā)送請求,client.indices()方法的返回值是IndicesClient類型,封裝了所有與索引庫操作有關(guān)的方法。
5.2.4.刪除索引庫
刪除索引庫的DSL語句非常簡單:
?DELETE /hotel
與創(chuàng)建索引庫相比:
請求方式從PUT變?yōu)镈ELTE
請求路徑不變
無請求參數(shù)
所以代碼的差異,注意體現(xiàn)在Request對象上。依然是三步走:
1)創(chuàng)建Request對象。這次是DeleteIndexRequest對象
2)準(zhǔn)備參數(shù)。這里是無參
3)發(fā)送請求。改用delete方法
在hotel-demo中的HotelIndexTest測試類中,編寫單元測試,實現(xiàn)刪除索引:
5.2.5.判斷索引庫是否存在
判斷索引庫是否存在,本質(zhì)就是查詢,對應(yīng)的DSL是:
?GET /hotel
因此與刪除的Java代碼流程是類似的。依然是三步走:
1)創(chuàng)建Request對象。這次是GetIndexRequest對象
2)準(zhǔn)備參數(shù)。這里是無參
3)發(fā)送請求。改用exists方法
5.2.5.總結(jié)
JavaRestClient操作elasticsearch的流程基本類似。核心是client.indices()方法來獲取索引庫的操作對象。
索引庫操作的基本步驟:
初始化RestHighLevelClient
創(chuàng)建XxxIndexRequest。XXX是Create、Get、Delete
準(zhǔn)備DSL( Create時需要,其它是無參)
發(fā)送請求。調(diào)用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete
5.3 操作文檔
為了與索引庫操作分離,我們再次參加一個測試類,做兩件事情:
初始化RestHighLevelClient
我們的酒店數(shù)據(jù)在數(shù)據(jù)庫,需要利用IHotelService去查詢,所以注入這個接口
5.3.1.新增文檔
我們要將數(shù)據(jù)庫的酒店數(shù)據(jù)查詢出來,寫入elasticsearch中。
數(shù)據(jù)庫查詢后的結(jié)果是一個Hotel類型的對象。結(jié)構(gòu)如下:
與我們的索引庫結(jié)構(gòu)存在差異:
longitude和latitude需要合并為location
因此,我們需要定義一個新的類型,與索引庫結(jié)構(gòu)吻合:
我們導(dǎo)入酒店數(shù)據(jù),基本流程一致,但是需要考慮幾點變化:
酒店數(shù)據(jù)來自于數(shù)據(jù)庫,我們需要先查詢出來,得到hotel對象
hotel對象需要轉(zhuǎn)為HotelDoc對象
HotelDoc需要序列化為json格式
因此,代碼整體步驟如下:
1)根據(jù)id查詢酒店數(shù)據(jù)Hotel
2)將Hotel封裝為HotelDoc
3)將HotelDoc序列化為JSON
4)創(chuàng)建IndexRequest,指定索引庫名和id
5)準(zhǔn)備請求參數(shù),也就是JSON文檔
6)發(fā)送請求
在項目的HotelDocumentTest測試類中,編寫單元測試:
5.3.2 查詢文檔
與之前類似,也是三步走:
1)準(zhǔn)備Request對象。這次是查詢,所以是GetRequest
2)發(fā)送請求,得到結(jié)果。因為是查詢,這里調(diào)用client.get()方法
3)解析結(jié)果,就是對JSON做反序列化
在項目的HotelDocumentTest測試類中,編寫單元測試:
5.3.3.刪除文檔
刪除的DSL為是這樣的:
?DELETE /hotel/_doc/{id}
與查詢相比,僅僅是請求方式從DELETE變成GET,可以想象Java代碼應(yīng)該依然是三步走:
1)準(zhǔn)備Request對象,因為是刪除,這次是DeleteRequest對象。要指定索引庫名和id
2)準(zhǔn)備參數(shù),無參
3)發(fā)送請求。因為是刪除,所以是client.delete()方法
在項目的HotelDocumentTest測試類中,編寫單元測試:
5.3.4 修改文檔
與之前類似,也是三步走:
1)準(zhǔn)備Request對象。這次是修改,所以是UpdateRequest
2)準(zhǔn)備參數(shù)。也就是JSON文檔,里面包含要修改的字段
3)更新文檔。這里調(diào)用client.update()方法
在項目的HotelDocumentTest測試類中,編寫單元測試:
5.3.5.批量導(dǎo)入文檔
案例需求:利用BulkRequest批量將數(shù)據(jù)庫數(shù)據(jù)導(dǎo)入到索引庫中。
步驟如下:
利用mybatis-plus查詢酒店數(shù)據(jù)
將查詢到的酒店數(shù)據(jù)(Hotel)轉(zhuǎn)換為文檔類型數(shù)據(jù)(HotelDoc)
利用JavaRestClient中的BulkRequest批處理,實現(xiàn)批量新增文檔
批量處理BulkRequest,其本質(zhì)就是將多個普通的CRUD請求組合在一起發(fā)送。
其中提供了一個add方法,用來添加其他請求:

可以看到,能添加的請求包括:
IndexRequest,也就是新增
UpdateRequest,也就是修改
DeleteRequest,也就是刪除
其實還是三步走:
1)創(chuàng)建Request對象。這里是BulkRequest
2)準(zhǔn)備參數(shù)。批處理的參數(shù),就是其它Request對象,這里就是多個IndexRequest
3)發(fā)起請求。這里是批處理,調(diào)用的方法為client.bulk()方法
在項目的HotelDocumentTest測試類中,編寫單元測試:
5.3.6.小結(jié)
文檔操作的基本步驟:
初始化RestHighLevelClient
創(chuàng)建XxxRequest。XXX是Index、Get、Update、Delete、Bulk
準(zhǔn)備參數(shù)(Index、Update、Bulk時需要)
發(fā)送請求。調(diào)用RestHighLevelClient#.xxx()方法,xxx是index、get、update、delete、bulk
解析結(jié)果(Get時需要)