【從0到1學Elasticsearch】Elasticsearch從入門到精通(上)

黑馬商城作為一個電商項目,商品的搜索肯定是訪問頻率最高的頁面之一。目前搜索功能是基于數據庫的模糊搜索來實現的,存在很多問題。
首先,查詢效率較低。
由于數據庫模糊查詢不走索引,在數據量較大的時候,查詢性能很差。
需要注意的是,數據庫模糊查詢隨著表數據量的增多,查詢性能的下降會非常明顯,而搜索引擎的性能則不會隨著數據增多而下降太多。目前僅10萬不到的數據量差距就如此明顯,如果數據量達到百萬、千萬、甚至上億級別,這個性能差距會非常夸張。
其次,功能單一,數據庫的模糊搜索匹配條件非常苛刻,例如,當我們需要查詢java基礎課程的時候,如果按照這種查詢方式,我們查詢出來的就只能是(---------java基礎課程--------)前后匹配,那么如果一個店鋪售賣的名為,(java課程,幫助你打好java基礎)那么這個店鋪售賣的東西就不會被搜索出來

目前全球的搜索引擎技術排名如下:
在這里插入圖片描述
Elasticsearch功能有很多

  • 1 例如github上的代碼搜索
  • 2 商品信息搜索
  • 3 解決方案搜搜哦
  • 4 附近商鋪,打車搜索

初識Elasticsearch

Elasticsearch是由elastic公司開發的一套搜索引擎技術,它是elastic技術棧中的一部分。完整的技術棧包括:

  • Elasticsearch:用于數據存儲、計算和搜索
  • Logstash/Beats:用于數據收集
  • Kibana:用于數據可視化

安裝Elasticsearch

我們依舊采用的是docker安裝,簡單方便

docker run -d \--name es \-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \  -e "discovery.type=single-node" \-v es-data:/usr/share/elasticsearch/data \-v es-plugins:/usr/share/elasticsearch/plugins \--privileged \--network hm-net \-p 9200:9200 \-p 9300:9300 \elasticsearch:7.12.1

安裝完成之后訪問9200端口可以看到基本信息

安裝Kibana

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=hm-net \
-p 5601:5601  \
kibana:7.12.1

安裝完成之后訪問5601端口,可以看到控制臺頁面
在這里插入圖片描述

倒排索引

elasticsearch之所以有如此高性能的搜索表現,正是得益于底層的倒排索引技術。我們首先來看看什么是正向索引。

正向索引

例如我們在mysql當中有一張goods的表

idtitleprice
1小米手機3499
2華為手機4999
3華為小米充電器49
4小米手環49

其中的id字段已經創建了索引,由于索引底層采用了B+樹結構,因此我們根據id搜索的速度會非常快。但是其他字段例如title,只在葉子節點上存在。
因此要根據title搜索的時候只能遍歷樹中的每一個葉子節點,判斷title數據是否符合要求。

select * from tb_goods where title like '%手機%';

流程如下
在這里插入圖片描述
說明:

  • 1)檢查到搜索條件為like ‘%手機%’,需要找到title中包含手機的數據
  • 2)逐條遍歷每行數據(每個葉子節點),比如第1次拿到id為1的數據
  • 3)判斷數據中的title字段值是否符合條件
  • 4)如果符合則放入結果集,不符合則丟棄
  • 5)回到步驟1

綜上所述,如果我們根據有索引的id進行查詢,那么查詢效率就會非常高,但是如果搜索條件為模糊匹配時,由于索引無法生效,導致從索引查詢退化為全表掃描,效率很差。
因此,正向索引適合于根據索引字段的精確搜索,不適合基于部分詞條的模糊匹配。
而倒排索引恰好解決的就是根據部分詞條模糊匹配的問題。

倒排索引

倒排索引中有兩個非常重要的概念:

  • 文檔(Document):用來搜索的數據,其中的每一條數據就是一個文檔。例如一個網頁、一個商品信息
  • 詞條(Term):對文檔數據或用戶搜索數據,利用某種算法分詞,得到的具備含義的詞語就是詞條。例如:我是中國人,就可以分為:我、是、中國人、中國、國人這樣的幾個詞條

倒排索引的搜索流程如下(以搜索"華為手機"為例),如圖:
在這里插入圖片描述
流程描述:
1)用戶輸入條件"華為手機"進行搜索。
2)對用戶輸入條件分詞,得到詞條:華為、手機。
3)拿著詞條在倒排索引中查找(由于詞條有索引,查詢效率很高),即可得到包含詞條的文檔id:1、2、3。
4)拿著文檔id到正向索引中查找具體文檔即可(由于id也有索引,查詢效率也很高)。

雖然要先查詢倒排索引,再查詢倒排索引,但是無論是詞條、還是文檔id都建立了索引,查詢速度非常快!無需全表掃描。

基礎概念

elasticsearch是面向文檔(Document)存儲的,可以是數據庫中的一條商品數據,一個訂單信息。文檔數據會被序列化為json格式后存儲在elasticsearch中:

在mysq當中數據存儲方式如下:
在這里插入圖片描述
但是在es當中如下

{"id": 1,"title": "小米手機","price": 3499
}
{"id": 2,"title": "華為手機","price": 4999
}
{"id": 3,"title": "華為小米充電器","price": 49
}
{"id": 4,"title": "小米手環","price": 299
}

因此,原本數據庫中的一行數據就是ES中的一個JSON文檔;而數據庫中每行數據都包含很多列,這些列就轉換為JSON文檔中的字段(Field)。

索引和映射

隨著業務發展,需要在es中存儲的文檔也會越來越多,比如有商品的文檔、用戶的文檔、訂單文檔等等:
在這里插入圖片描述
所有文檔都散亂存放顯然非常混亂,也不方便管理。
因此,我們要將類型相同的文檔集中在一起管理,稱為索引(Index)。例如:
商品索引:

{"id": 1,"title": "小米手機","price": 3499
}{"id": 2,"title": "華為手機","price": 4999
}{"id": 3,"title": "三星手機","price": 3999
}

用戶索引

{"id": 101,"name": "張三","age": 21
}{"id": 102,"name": "李四","age": 24
}{"id": 103,"name": "麻子","age": 18
}

Mysql與Es

TableIndex索引(index),就是文檔的集合,類似數據庫的表(table)
RowDocument文檔(Document),就是一條條的數據,類似數據庫中的行(Row),文檔都是JSON格式
ColumnField字段(Field),就是JSON文檔中的字段,類似數據庫中的列(Column)
SchemaMappingMapping(映射)是索引中文檔的約束,例如字段類型約束。類似數據庫的表結構(Schema)
SQLDSLDSL是elasticsearch提供的JSON風格的請求語句,用來操作elasticsearch,實現CRUD

如圖
在這里插入圖片描述
那是不是說,我們學習了elasticsearch就不再需要mysql了呢?
并不是如此,兩者各自有自己的擅長之處:

  • Mysql:擅長事務類型操作,可以確保數據的安全和一致性
  • Elasticsearch:擅長海量數據的搜索、分析、計算

因此在企業中,往往是兩者結合使用:

  • 對安全性要求較高的寫操作,使用mysql實現
  • 對查詢性能要求較高的搜索需求,使用elasticsearch實現
  • 兩者再基于某種方式,實現數據的同步,保證一致性

在這里插入圖片描述

IK分詞器

愛坤分詞器(露出雞腳了),es關鍵的就是倒排索引,而倒排索引依賴對文檔內部的詞進行分詞,而分詞則需要高效、精準的分詞算法,IK分詞器就是這樣一個中文分詞算法。

安裝IK分詞器

同樣是docker
方案1:在線安裝

docker exec -it es ./bin/elasticsearch-plugin  install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip

安裝完成之后重啟es

docker restart es

方案2:離線安裝
首先,查看之前安裝的Elasticsearch容器的plugins數據卷目錄:

docker volume inspect es-plugins
[{"CreatedAt": "2024-11-06T10:06:34+08:00","Driver": "local","Labels": null,"Mountpoint": "/var/lib/docker/volumes/es-plugins/_data","Name": "es-plugins","Options": null,"Scope": "local"}
]

可以看到elasticsearch的插件掛載到了/var/lib/docker/volumes/es-plugins/_data這個目錄。我們需要把IK分詞器上傳至這個目錄。
上傳完成之后重啟es容器

簡單使用

IK分詞器包含兩種模式:

  • ik_smart:智能語義切分
  • ik_max_word:最細粒度切分

首先我們來看看官方提供的標準分詞方式

POST /_analyze
{"analyzer": "standard","text": "黑馬程序員學習java太棒了"
}
{"tokens" : [{"token" : "黑","start_offset" : 0,"end_offset" : 1,"type" : "<IDEOGRAPHIC>","position" : 0},{"token" : "馬","start_offset" : 1,"end_offset" : 2,"type" : "<IDEOGRAPHIC>","position" : 1},{"token" : "程","start_offset" : 2,"end_offset" : 3,"type" : "<IDEOGRAPHIC>","position" : 2},{"token" : "序","start_offset" : 3,"end_offset" : 4,"type" : "<IDEOGRAPHIC>","position" : 3},{"token" : "員","start_offset" : 4,"end_offset" : 5,"type" : "<IDEOGRAPHIC>","position" : 4},{"token" : "學","start_offset" : 5,"end_offset" : 6,"type" : "<IDEOGRAPHIC>","position" : 5},{"token" : "習","start_offset" : 6,"end_offset" : 7,"type" : "<IDEOGRAPHIC>","position" : 6},{"token" : "java","start_offset" : 7,"end_offset" : 11,"type" : "<ALPHANUM>","position" : 7},{"token" : "太","start_offset" : 11,"end_offset" : 12,"type" : "<IDEOGRAPHIC>","position" : 8},{"token" : "棒","start_offset" : 12,"end_offset" : 13,"type" : "<IDEOGRAPHIC>","position" : 9},{"token" : "了","start_offset" : 13,"end_offset" : 14,"type" : "<IDEOGRAPHIC>","position" : 10}]
}

我們可以看到,他對中文的分詞能力很差,一個字分一下,而對英文的java的分詞效果很好。

我們再測試IK分詞器:

POST /_analyze
{"analyzer": "ik_smart","text": "黑馬程序員學習java太棒了"
}
{"tokens" : [{"token" : "黑馬","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 0},{"token" : "程序員","start_offset" : 2,"end_offset" : 5,"type" : "CN_WORD","position" : 1},{"token" : "學習","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 2},{"token" : "java","start_offset" : 7,"end_offset" : 11,"type" : "ENGLISH","position" : 3},{"token" : "太棒了","start_offset" : 11,"end_offset" : 14,"type" : "CN_WORD","position" : 4}]
}
拓展詞典

隨著互聯網的發展,“造詞運動”也越發的頻繁。出現了很多新的詞語,在原有的詞匯列表中并不存在。比如:“泰褲辣”,“傳智播客” 等。而IK分詞器無法對這些詞匯分詞。
所以要想正確分詞,IK分詞器的詞庫也需要不斷的更新,IK分詞器提供了擴展詞匯的功能。
1)打開IK分詞器config目錄:
在這里插入圖片描述

2)在IKAnalyzer.cfg.xml配置文件內容添加:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 擴展配置</comment><!--用戶可以在這里配置自己的擴展字典 *** 添加擴展詞典--><entry key="ext_dict">ext.dic</entry>
</properties>

3)在IK分詞器的config目錄新建一個 ext.dic,可以參考config目錄下復制一個配置文件進行修改

傳智播客
泰褲辣

4)重啟elasticsearch

此外我們還可以添加斷分詞的字段,同樣是在IKAnalyzer.cfg.xml里配置,注意在線安裝的話沒有config目錄,但是也不要手動創建config目錄,具體解決方法可以在網上搜索。

索引庫操作

Mapping映射屬性

Mapping是對索引庫中文檔的約束,常見的Mapping屬性包括:

  • type:字段數據類型,常見的簡單類型有:
    • 字符串:text(可分詞的文本)、keyword(精確值,例如:品牌、國家、ip地址)
    • 數值:long、integer、short、byte、double、float、
    • 布爾:boolean
    • 日期:date
    • 對象:object
  • index:是否創建索引,默認為true
  • analyzer:使用哪種分詞器
  • properties:該字段的子字段

索引庫的CRUD

創建索引庫與映射

基本語法:

  • 請求方式:PUT
  • 請求路徑:/索引庫名,可以自定義
  • 請求參數:mapping映射
PUT /索引庫名稱
{"mappings": {"properties": {"字段名":{"type": "text","analyzer": "ik_smart"},"字段名2":{"type": "keyword","index": "false"},"字段名3":{"properties": {"子字段": {"type": "keyword"}}},// ...略}}
}

例子

## 創建索引庫并且設置mapping映射
PUT /heima
{"mappings": {"properties": {"info":{"type": "text","analyzer": "ik_smart"  // 分詞其類型},"age":{"type": "byte"},"email":{"type": "keyword","index": false  // 不創建索引},"name":{"type": "object","properties": {"fistName":{"type": "keyword"   },"lastName":{"type": "keyword"}}}}}
}
查詢索引庫

基本語法:

  • 請求方式:GET
  • 請求路徑:/索引庫名
  • 請求參數:無
GET /索引庫名
修改索引庫

倒排索引結構雖然不復雜,但是一旦數據結構改變(比如改變了分詞器),就需要重新創建倒排索引,這簡直是災難。因此索引庫一旦創建,無法修改mapping。

雖然無法修改mapping中已有的字段,但是卻允許添加新的字段到mapping中,因為不會對倒排索引產生影響。因此修改索引庫能做的就是向索引庫中添加新字段,或者更新索引庫的基礎屬性

PUT /索引庫名/_mapping
{"properties": {"新字段名":{"type": "integer"}}
}
刪除索引庫

語法:

  • 請求方式:DELETE
  • 請求路徑:/索引庫名
  • 請求參數:無
DELETE /索引庫名

文檔操作

新增文檔

POST /索引庫名/_doc/文檔id
{"字段1": "值1","字段2": "值2","字段3": {"子屬性1": "值3","子屬性2": "值4"},
}

查詢文檔

根據rest風格,新增是post,查詢應該是get,不過查詢一般都需要條件,這里我們把文檔id帶上。

GET /{索引庫名稱}/_doc/{id}

在這里插入圖片描述

刪除文檔

就不用多說了肯定是delete

DELETE /{索引庫名}/_doc/id值

修改文檔

修改文檔由兩種方式:

  • 全量修改:直接覆蓋原來的文檔
  • 局部修改:根據提供的字段進行修改
全量修改

全量修改的方法和新增文檔的方法一樣
全量修改是覆蓋原來的文檔,其本質是兩步操作:

  • 根據指定的id刪除文檔
  • 新增一個相同id的文檔
PUT /{索引庫名}/_doc/文檔id
{"字段1": "值1","字段2": "值2",// ... 略
}

這時候如果寫了一個不存在的id那么就是新增

局部修改

局部修改是只修改指定id匹配的文檔中的部分字段。

POST /{索引庫名}/_update/文檔id
{"doc": {"字段名": "新的值",}
}

批處理

批量處理的代碼如下

POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

RestAPI

在elasticsearch提供的API中,與elasticsearch一切交互都封裝在一個名為RestHighLevelClient的類中,必須先完成這個對象的初始化,建立與elasticsearch的連接。

初始化連接

分為三步:
1)在item-service模塊中引入es的RestHighLevelClient依賴:

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

2)因為SpringBoot默認的ES版本是7.17.10,所以我們需要覆蓋默認的ES版本:

<properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

3)初始化RestHighLevelClient:

RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.150.101:9200")
));
@Configuration
public class ElasticClient {@Bean(destroyMethod = "close")@ConditionalOnMissingBeanpublic RestHighLevelClient restHighLevelClient() {return new RestHighLevelClient(RestClient.builder(new HttpHost("192.168.200.200",9200,"http")));}}

創建索引庫

Mapping映射

最終我們需要改造黑馬商城的搜索業務,經過我們分析,原本的增加代碼如下

PUT /items
{"mappings": {"properties": {"id": {"type": "keyword"},"name":{"type": "text","analyzer": "ik_max_word"},"price":{"type": "integer"},"stock":{"type": "integer"},"image":{"type": "keyword","index": false},"category":{"type": "keyword"},"brand":{"type": "keyword"},"sold":{"type": "integer"},"commentCount":{"type": "integer","index": false},"isAD":{"type": "boolean"},"updateTime":{"type": "date"}}}
}
創建索引

創建索引的API如下
在這里插入圖片描述
代碼分為三步:

  • 1)創建Request對象。
    • 因為是創建索引庫的操作,因此Request是CreateIndexRequest。
  • 2)添加請求參數
    • 其實就是Json格式的Mapping映射參數。因為json字符串很長,這里是定義了靜態字符串常量MAPPING_TEMPLATE,讓代碼看起來更加優雅。
  • 3)發送請求
    • client.indices()方法的返回值是IndicesClient類型,封裝了所有與索引庫操作有關的方法。例如創建索引、刪除索引、判斷索引是否存在等
@Test
void testCreateIndex() throws IOException {// 1.創建Request對象CreateIndexRequest request = new CreateIndexRequest("items");// 2.準備請求參數request.source(MAPPING_TEMPLATE, XContentType.JSON);// 3.發送請求client.indices().create(request, RequestOptions.DEFAULT);
}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" +"      },\n" +"      \"price\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"stock\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"image\":{\n" +"        \"type\": \"keyword\",\n" +"        \"index\": false\n" +"      },\n" +"      \"category\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"brand\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"sold\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"commentCount\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"isAD\":{\n" +"        \"type\": \"boolean\"\n" +"      },\n" +"      \"updateTime\":{\n" +"        \"type\": \"date\"\n" +"      }\n" +"    }\n" +"  }\n" +"}";

刪除索引庫

不用多說對象為DeleteIndexRequest

@Test
void testDeleteIndex() throws IOException {// 1.創建Request對象DeleteIndexRequest request = new DeleteIndexRequest("items");// 2.發送請求client.indices().delete(request, RequestOptions.DEFAULT);
}

判斷索引庫是否存在

不用多說對象為GetIndexRequest

@Test
void testExistsIndex() throws IOException {// 1.創建Request對象GetIndexRequest request = new GetIndexRequest("items");// 2.發送請求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);// 3.輸出System.err.println(exists ? "索引庫已經存在!" : "索引庫不存在!");
}

RestClient文檔操作

新增文檔

新增文檔的API如下

POST /{索引庫名}/_doc/1
{"name": "Jack","age": 21
}

在這里插入圖片描述
可以看到與索引庫操作的API非常類似,同樣是三步走:

  • 1)創建Request對象,這里是IndexRequest,因為添加文檔就是創建倒排索引的過程
  • 2)準備請求參數,本例中就是Json文檔
  • 3)發送請求

變化的地方在于,這里直接使用client.xxx()的API,不再需要client.indices()了。

@Test
void testAddDocument() throws IOException {// 1.根據id查詢商品數據Item item = itemService.getById(100002644680L);// 2.轉換為文檔類型ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);// 3.將ItemDTO轉jsonString doc = JSONUtil.toJsonStr(itemDoc);// 1.準備Request對象IndexRequest request = new IndexRequest("items").id(itemDoc.getId());// 2.準備Json文檔request.source(doc, XContentType.JSON);// 3.發送請求client.index(request, RequestOptions.DEFAULT);
}

查詢文檔

查詢的請求語句如下:

GET /{索引庫名}/_doc/{id}

與之前的流程類似,代碼大概分2步:

  • 創建Request對象
  • 準備請求參數,這里是無參,直接省略
  • 發送請求

在這里插入圖片描述
可以看到,響應結果是一個JSON,其中文檔放在一個_source屬性中,因此解析就是拿到_source,反序列化為Java對象即可。

其它代碼與之前類似,流程如下:

  • 1)準備Request對象。這次是查詢,所以是GetRequest
  • 2)發送請求,得到結果。因為是查詢,這里調用client.get()方法
  • 3)解析結果,就是對JSON做反序列化
@Test
void testGetDocumentById() throws IOException {// 1.準備Request對象GetRequest request = new GetRequest("items").id("100002644680");// 2.發送請求GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.獲取響應結果中的sourceString json = response.getSourceAsString();ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);System.out.println("itemDoc= " + ItemDoc);
}

刪除文檔

刪除的請求語句如下:

DELETE /hotel/_doc/{id}

與查詢相比,僅僅是請求方式從DELETE變成GET,可以想象Java代碼應該依然是2步走:

  • 1)準備Request對象,因為是刪除,這次是DeleteRequest對象。要指定索引庫名和id
  • 2)準備參數,無參,直接省略
  • 3)發送請求。因為是刪除,所以是client.delete()方法
@Test
void testDeleteDocument() throws IOException {// 1.準備Request,兩個參數,第一個是索引庫名,第二個是文檔idDeleteRequest request = new DeleteRequest("item", "100002644680");// 2.發送請求client.delete(request, RequestOptions.DEFAULT);
}

修改文檔

我們上面說修改文檔由兩種方法,但是第一種方法我們肯定是不推薦的,因此這里直接看第二種方法

POST /{索引庫名}/_update/{id}
{"doc": {"字段名": "字段值","字段名": "字段值"}
}

在這里插入圖片描述

@Test
void testUpdateDocument() throws IOException {// 1.準備RequestUpdateRequest request = new UpdateRequest("items", "100002644680");// 2.準備請求參數request.doc("price", 58800,"commentCount", 1);// 3.發送請求client.update(request, RequestOptions.DEFAULT);
}

批量導入文檔

在之前的案例中,我們都是操作單個文檔。而數據庫中的商品數據實際會達到數十萬條,某些項目中可能達到數百萬條。
我們如果要將這些數據導入索引庫,肯定不能逐條導入,而是采用批處理方案。常見的方案有:

  • 利用Logstash批量導入
    • 需要安裝Logstash
    • 對數據的再加工能力較弱
    • 無需編碼,但要學習編寫Logstash導入配置
  • 利用JavaAPI批量導入
    • 需要編碼,但基于JavaAPI,學習成本低
    • 更加靈活,可以任意對數據做再加工處理后寫入索引庫
語法說明

批處理與前面講的文檔的CRUD步驟基本一致:

  • 創建Request,但這次用的是BulkRequest
  • 準備請求參數
  • 發送請求,這次要用到client.bulk()方法

BulkRequest本身其實并沒有請求參數,其本質就是將多個普通的CRUD請求組合在一起發送。例如:

  • 批量新增文檔,就是給每個文檔創建一個IndexRequest請求,然后封裝到BulkRequest中,一起發出。
  • 批量刪除,就是創建N個DeleteRequest請求,然后封裝到BulkRequest,一起發出

在這里插入圖片描述
可以看到,能添加的請求有:

  • IndexRequest,也就是新增
  • UpdateRequest,也就是修改
  • DeleteRequest,也就是刪除

示例

@Test
void testBulk() throws IOException {// 1.創建RequestBulkRequest request = new BulkRequest();// 2.準備請求參數request.add(new IndexRequest("items").id("1").source("json doc1", XContentType.JSON));request.add(new IndexRequest("items").id("2").source("json doc2", XContentType.JSON));// 3.發送請求client.bulk(request, RequestOptions.DEFAULT);
}

完整代碼

@Test
void testLoadItemDocs() throws IOException {// 分頁查詢商品數據int pageNo = 1;int size = 1000;while (true) {Page<Item> page = itemService.lambdaQuery().eq(Item::getStatus, 1).page(new Page<Item>(pageNo, size));// 非空校驗List<Item> items = page.getRecords();if (CollUtils.isEmpty(items)) {return;}log.info("加載第{}頁數據,共{}條", pageNo, items.size());// 1.創建RequestBulkRequest request = new BulkRequest("items");// 2.準備參數,添加多個新增的Requestfor (Item item : items) {// 2.1.轉換為文檔類型ItemDTOItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);// 2.2.創建新增文檔的Request對象request.add(new IndexRequest().id(itemDoc.getId()).source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON));}// 3.發送請求client.bulk(request, RequestOptions.DEFAULT);// 翻頁pageNo++;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901269.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901269.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901269.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖論基礎理論

在我看來&#xff0c;想要掌握圖的基礎應用&#xff0c;僅需要三步走。 什么是圖&#xff08;基本概念&#xff09;、圖的構造&#xff08;打地基&#xff09;、圖的遍歷方式&#xff08;應用的基礎&#xff09; 只要能OK的掌握這三步、就算圖論入門了&#xff01;&#xff0…

詳細解讀react框架中的hooks

React Hooks 是 React 16.8 引入的一項革命性特性&#xff0c;它允許你在函數組件中使用狀態(state)和其他 React 特性&#xff0c;而無需編寫 class 組件。下面將詳細解讀 React Hooks 的核心概念、常用 Hooks 及其工作原理。 一、Hooks 的核心概念 1. 什么是 Hooks Hooks …

主機IP動態變化時如何通過固定host.docker.internal訪問本機服務

場景需求——主機IP動態變化時&#xff0c;通過固定的 http://host.docker.internal:11555 訪問本機服務&#xff0c;核心問題在于 host.docker.internal 的解析邏輯與動態IP的適配。以下是分步解決方案&#xff1a; 一、核心原理&#xff1a;host.docker.internal 的本質與局…

插值算法 - 最近鄰插值實現

目錄 1. 導入必要的庫 2. nearest_neighbor_interpolation 3. 測試代碼 數學原理 完整代碼 本文實現了基于最近鄰插值算法的圖像縮放功能。 它使用 Python 編寫,主要依賴于NumPy和PIL(Python Imaging Library)庫。 NumPy用于高效的數值計算,而PIL僅用于圖像的加載和…

windows中搭建Ubuntu子系統

windows中搭建虛擬環境 1.配置2.windows中搭建Ubuntu子系統2.1windows配置2.1.1 確認啟用私有化2.1.2 將wsl2設置為默認版本2.1.3 確認開啟相關配置2.1.4重啟windows以加載更改配置 2.2 搭建Ubuntu子系統2.2.1 下載Ubuntu2.2.2 遷移位置 3.Ubuntu子系統搭建docker環境3.1安裝do…

MySQL事務機制

目錄 原子性 持久性 隔離性 隔離級別(并發事務之間的關系) 讀未提交 讀已提交 可重復讀 串行化(最嚴格的隔離級別) 一致性 問題 不可重復讀性(已經提交的數據) 什么是臟讀問題(未提交的數據)? 幻讀 保存點 自動提交機制--autocommit 會話隔離級別與全局隔離級…

Cadence學習筆記之---直插元件的封裝制作

目錄 01 | 引 言 02 | 環境描述 03 | 操作步驟 04 | 結 語 01 | 引 言 在之前發布的Cadence小記中&#xff0c;已經講述了怎樣制作熱風焊盤&#xff0c;貼片(SMD)焊盤、通孔、過孔&#xff0c;以及貼片元件的封裝。 本篇關于Cadence的小記主要講如何制作直插元件的封裝。 …

【第四十周】文獻閱讀:用于檢索-增強大語言模型的查詢與重寫

目錄 摘要Abstract用于檢索-增強大語言模型的查詢與重寫研究背景方法論基于凍結LLM的重寫方案基于可訓練重寫器的方案重寫器預熱訓練&#xff08;Rewriter Warm-up&#xff09;強化學習&#xff08;Reinforcement Learning&#xff09; 創新性實驗結果局限性總結 摘要 這篇論文…

java學習總結(if switch for)

一.基本結構 1.單分支if int num 10; if (num > 5) {System.out.println("num 大于 5"); } 2.雙分支if-else int score 60; if (score > 60) {System.out.println("及格"); } else {System.out.println("不及格"); } 3.多分支 int…

yum的基本操作和vim指令

在我們的手機端或者Windows上下載軟件&#xff0c;可以在相應的應用商店或者官網進行下載&#xff0c;這樣對于用戶來說十分的方便和便捷。而在Linux上&#xff0c;也有類似的安裝方式&#xff0c;我們來一一了解一下。 Linux安裝軟件的3種方法 源代碼安裝 在Linux下安裝軟件…

C++ CUDA開發入門

CUDA開發筆記 文章目錄 CUDA開發筆記[toc]1 概述2 環境3 命令行編譯4 CMAKE引入CUDA5 vscode開發CUDA6 Qt中使用CUDA-CMake7 QMake配置CUDA8 核函數9 核函數調用9.1 核函數調用語法9.2 執行配置參數詳解9.3 關鍵調用步驟9.4 重要注意事項9.5 調用示例分析9.6 最佳實踐建議 10 線…

llm開發框架新秀

原文鏈接:https://i68.ltd/notes/posts/20250404-llm-framework3/ google開源ADK-Agent Development Kit 開源的、代碼優先的 Python 工具包&#xff0c;用于構建、評估和部署具有靈活性和控制力的復雜智能體項目倉庫:https://github.com/google/adk-python 2.6k項目文檔:Age…

VM——相機拍照失敗

1、問題&#xff1a;相機頻閃觸發&#xff0c;在MVS中正常出圖&#xff0c;在VM中出現拍照失敗 2、解決&#xff1a; 1、首先排查網絡設置&#xff08;巨幀是否設置&#xff09; 2、電腦的所有防火墻是否關閉 3、在MVS中恢復相機的設置參數為默認參數&#xff0c;刪除VM中的全…

【時頻譜分析】小波分析

算法配置頁面&#xff0c;也可以一鍵導出結果數據 報表自定義繪制 獲取和下載【PHM學習軟件PHM源碼】的方式 獲取方式&#xff1a;Docshttps://jcn362s9p4t8.feishu.cn/wiki/A0NXwPxY3ie1cGkOy08cru6vnvc

怎么免費下載GLTF/GLB格式模型文件,還可以在線編輯修改

? 現在非常流行glb格式模型&#xff0c;和gltf格式文件&#xff0c;可是之類模型網站非常非常少 1&#xff0c;咱們先直接打開http://glbxz.com 官方glb下載網站 glbxz.com 2 可以搜索&#xff0c;自己想要的模型關鍵詞 3&#xff0c;到自己想下載素材頁面 4&#xff0c;…

【6】深入學習http模塊(萬字)-Nodejs開發入門

深入學習http模塊 前言http一個Web服務器項目創建代碼運行代碼解析 Server屬性&#xff1a;keepAlive屬性&#xff1a;keepAliveTimeout屬性&#xff1a;maxHeaderSize屬性&#xff1a;requestTimeout屬性&#xff1a;maxRequestsPerSocket方法&#xff1a;close()方法&#xf…

buuctf sql注入類練習

BUU SQL COURSE 1 1 實例無法訪問 / Instance cant be reached at that time | BUUCTF但是這個地方很迷惑就是這個 一個 # 我們不抓包就不知道這個是sql注入類的判斷是 get 類型的sql注入直接使用sqlmap我們放入到1.txt中 目的是 優先檢測 ?id1>python3 sqlmap.py -r 1.t…

(即插即用模塊-特征處理部分) 三十二、(TGRS 2024) MDAF 多尺度雙表示對齊過濾器

文章目錄 1、Multiscale Dual-Representation Alignment Filter2、代碼實現 paper&#xff1a;SFFNet: A Wavelet-Based Spatial and Frequency Domain Fusion Network for Remote Sensing Segmentation Code&#xff1a;https://github.com/yysdck/SFFNet 1、Multiscale Dual-…

Python 中為什么 hash(-1) == hash(-2)?

推薦超級課程: 本地離線DeepSeek AI方案部署實戰教程【完全版】Docker快速入門到精通Kubernetes入門到大師通關課AWS云服務快速入門實戰目錄 讓我們從哪里開始?獲取源代碼!讓我們瀏覽一下這是正確/完整的答案嗎?結論前幾天在瀏覽 Reddit 時,我在 r/Python 上看到了這樣一個…

基于PySide6與pycatia的CATIA繪圖比例智能調節工具開發全解析

引言&#xff1a;工程圖紙自動化處理的技術革新 在機械設計領域&#xff0c;CATIA圖紙的比例調整是高頻且重復性極強的操作。傳統手動調整方式效率低下且易出錯。本文基于PySide6pycatia技術棧&#xff0c;提出一種支持智能比例匹配、實時視圖控制、異常自處理的圖紙批處理方案…