elasticSearch-搜索引擎

搜索引擎的優勢

有了數據庫分頁查詢,為什么還需要搜索引擎?

  • 搜索引擎速度上很快
  • 數據庫分頁查詢,隨著數據庫數據量增大,頁數靠后,會導致搜索速度變慢,但是搜索引擎不會
  • 搜索引擎支持分詞查詢,地理坐標搜索等

搜索引擎排名

  • 搜索引擎技術排名:
  1. Elasticsearch:搜索引擎
  2. Splunk:商目
  3. Solr:Apache

在這里插入圖片描述

認識與安裝elasticSearch

前世

Lucene是一個Java語言的搜索引擎類庫,是Apache公司的頂級項目,由DougCutting于1999年研發

Lucene的優勢:

  • 易擴展
  • 高性能(基于倒排索引)

今生

2004年Shay Banon基于Lucene開發了Compass
2010年Shay Banon 重寫了Compass,取名為Elasticsearch
官網地址:https:/www.elastic.co/cn/,目前最新的版本是:8.x.x

elasticsearch具備下列優勢:

  • 支持分布式,可水平擴展
  • 提供Restful接口,可被任何語言調用

結合

elasticsearch結合kibana、Logstash、Beats,是一整套技術棧,被叫做ELK。被廣泛應用在日志數據分析、實時監控等領域。

在這里插入圖片描述
在這里插入圖片描述

我們要安裝的內容包含2部分:

  • elasticsearch:存儲、搜索和運算
  • kibana:圖形化展示

首先Elasticsearch不用多說,是提供核心的數據存儲、搜索、分析功能的。
然后是Kibana,Elasticsearch對外提供的是Restful風格的API,任何操作都可以通過發送http請求來完成。不過http請求的方式、路徑、還有請求參數的格式都有嚴格的規范。這些規范我們肯定記不住,因此我們要借助于Kibana這個服務。
Kibana是elastic公司提供的用于操作Elasticsearch的可視化控制臺。它的功能非常強大,包括:

  • 對Elasticsearch數據的搜索、展示
  • 對Elasticsearch數據的統計、聚合,并形成圖形化報表、圖形
  • 對Elasticsearch的集群狀態監控
  • 它還提供了一個開發控制臺(DevTools),在其中對Elasticsearch的Restful的API接口提供了語法提示

安裝elasticSearch

通過下面的Docker命令即可安裝單機版本的elasticsearch:

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

注意,這里我們采用的是elasticsearch的7.12.1版本,由于8以上版本的JavaAPI變化很大,在企業中應用并不廣泛,企業中應用較多的還是8以下的版本。
如果拉取鏡像困難,可以直接導入課前資料提供的鏡像tar包:

在這里插入圖片描述
安裝完成后,訪問9200端口,即可看到響應的Elasticsearch服務的基本信息:

在這里插入圖片描述

安裝Kibana

通過下面的Docker命令,即可部署Kibana:

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

如果拉取鏡像困難,可以直接導入課前資料提供的鏡像tar包:
在這里插入圖片描述

安裝完成后,直接訪問5601端口,即可看到控制臺頁面:

在這里插入圖片描述
選擇Explore on my own之后,進入主頁面:
在這里插入圖片描述
然后選中Dev tools,進入開發工具頁面:

在這里插入圖片描述

倒排索引

傳統數據庫

傳統數據庫(如MySQL)采用正向索引,例如給下表(tb_goods)中的id創建索引:

在這里插入圖片描述

elasticSearch

elasticsearch采用倒排索引:

  • 文檔(document):每條數據就是一個文檔
  • 詞條(term):文檔按照語義分成的詞語

在這里插入圖片描述

在這里插入圖片描述

lk分詞器

中文分詞往往需要根據語義分析,比較復雜,這就需要用到中文分詞器,例如IK分詞器。IK分詞器是林良益在2006年開源發布的,其采用的正向迭代最細粒度切分算法一直沿用至今。

1.安裝IK分詞器

方案一:在線安裝
運行一個命令即可:

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

重啟

docker restart es

方案二:離線安裝
如果網速較差,也可以選擇離線安裝。
首先,查看之前安裝的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分詞器上傳至這個目錄。

找到課前資料提供的ik分詞器插件,課前資料提供了7.12.1版本的ik分詞器壓縮文件,你需要對其解壓:
在這里插入圖片描述
然后上傳至虛擬機的/var/lib/docker/volumes/es-plugins/_data這個目錄:
在這里插入圖片描述
最后,重啟es容器:

docker restart es

2.使用IK分詞器

IK分詞器包含兩種模式:

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

我們在Kibana的DevTools上來測試分詞器,首先測試Elasticsearch官方提供的標準分詞器:

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}]
}

可以看到,標準分詞器智能1字1詞條,無法正確對中文做分詞。
我們再測試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分詞器無法對這些詞匯分詞,測試一下:

POST /_analyze
{"analyzer": "ik_max_word","text": "傳智播客開設大學,真的泰褲辣!"
}

結果:

{"tokens" : [{"token" : "傳","start_offset" : 0,"end_offset" : 1,"type" : "CN_CHAR","position" : 0},{"token" : "智","start_offset" : 1,"end_offset" : 2,"type" : "CN_CHAR","position" : 1},{"token" : "播","start_offset" : 2,"end_offset" : 3,"type" : "CN_CHAR","position" : 2},{"token" : "客","start_offset" : 3,"end_offset" : 4,"type" : "CN_CHAR","position" : 3},{"token" : "開設","start_offset" : 4,"end_offset" : 6,"type" : "CN_WORD","position" : 4},{"token" : "大學","start_offset" : 6,"end_offset" : 8,"type" : "CN_WORD","position" : 5},{"token" : "真的","start_offset" : 9,"end_offset" : 11,"type" : "CN_WORD","position" : 6},{"token" : "泰","start_offset" : 11,"end_offset" : 12,"type" : "CN_CHAR","position" : 7},{"token" : "褲","start_offset" : 12,"end_offset" : 13,"type" : "CN_CHAR","position" : 8},{"token" : "辣","start_offset" : 13,"end_offset" : 14,"type" : "CN_CHAR","position" : 9}]
}

可以看到,傳智播客和泰褲辣都無法正確分詞。
所以要想正確分詞,IK分詞器的詞庫也需要不斷的更新,IK分詞器提供了擴展詞匯的功能。
1)打開IK分詞器config目錄:

在這里插入圖片描述
注意,如果采用在線安裝的通過,默認是沒有config目錄的,需要把課前資料提供的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

docker restart es# 查看 日志
docker logs -f elasticsearch

再次測試,可以發現傳智播客和泰褲辣都正確分詞了:

{"tokens" : [{"token" : "傳智播客","start_offset" : 0,"end_offset" : 4,"type" : "CN_WORD","position" : 0},{"token" : "開設","start_offset" : 4,"end_offset" : 6,"type" : "CN_WORD","position" : 1},{"token" : "大學","start_offset" : 6,"end_offset" : 8,"type" : "CN_WORD","position" : 2},{"token" : "真的","start_offset" : 9,"end_offset" : 11,"type" : "CN_WORD","position" : 3},{"token" : "泰褲辣","start_offset" : 11,"end_offset" : 14,"type" : "CN_WORD","position" : 4}]
}

總結

分詞器的作用是什么?

  • 創建倒排索引時,對文檔分詞
  • 用戶搜索時,對輸入的內容分詞

IK分詞器有幾種模式?

  • ik_smart:智能切分,粗粒度
  • ik_max_word:最細切分,細粒度

IK分詞器如何拓展詞條?如何停用詞條?

  • 利用config目錄的IkAnalyzer.cfg.xml文件添加拓展詞典和停用詞典
  • 在詞典中添加拓展詞條或者停用詞條

基本概念

  • 索引(index):相同類型的文檔的集合
  • 映射(mapping):索引中文檔的字段約束信息,類似表的結構約束

在這里插入圖片描述

數據庫和elasticSearch的對比

在這里插入圖片描述

Mapping的映射屬性

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

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

在這里插入圖片描述

restful規范

Elasticsearch提供的所有API都是Restful的接口,遵循Restful的基本規范:

在這里插入圖片描述

創建索引和mapping
在這里插入圖片描述
基本語法:

  • 請求方式:PUT
  • 請求路徑:/索引庫名,可以自定義
  • 請求參數:mapping映射

格式:

PUT /索引庫名稱
{"mappings": {"properties": {"字段名":{"type": "text","analyzer": "ik_smart"},"字段名2":{"type": "keyword","index": "false"},"字段名3":{"properties": {"子字段": {"type": "keyword"}}},// ...略}}
}

示例:

# PUT /heima
{"mappings": {"properties": {"info":{"type": "text","analyzer": "ik_smart"},"email":{"type": "keyword","index": "false"},"name":{"properties": {"firstName": {"type": "keyword"}}}}}
}

查詢索引庫

基本語法:

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

格式:

GET /索引庫名

示例:

GET /heima

修改索引庫

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

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

語法說明:

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

示例:

PUT /heima/_mapping
{"properties": {"age":{"type": "integer"}}
}

刪除索引庫

語法:

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

格式:

DELETE /索引庫名

示例:

DELETE /heima

總結

索引庫操作有哪些?

  • 創建索引庫:PUT /索引庫名
  • 查詢索引庫:GET /索引庫名
  • 刪除索引庫:DELETE /索引庫名
  • 修改索引庫,添加字段:PUT /索引庫名/_mapping

可以看到,對索引庫的操作基本遵循的Restful的風格,因此API接口非常統一,方便記憶。

文檔操作

crud操作

有了索引庫,接下來就可以向索引庫中添加數據了。
Elasticsearch中的數據其實就是JSON風格的文檔。操作文檔自然保護增、刪、改、查等幾種常見操作,我們分別來學習。

1.新增文檔

語法:

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

示例:

POST /heima/_doc/1
{"info": "黑馬程序員Java講師","email": "zy@itcast.cn","name": {"firstName": "云","lastName": "趙"}
}

響應:
在這里插入圖片描述

2.查詢文檔

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

語法:

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

示例:

GET /heima/_doc/1

查看結果:
在這里插入圖片描述

3.刪除文檔

刪除使用DELETE請求,同樣,需要根據id進行刪除:

語法:

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

示例:

DELETE /heima/_doc/1

結果:

在這里插入圖片描述

4.修改文檔

修改有兩種方式:

  • 全量修改:直接覆蓋原來的文檔
  • 局部修改:修改文檔中的部分字段
4.1.全量修改

全量修改是覆蓋原來的文檔,其本質是兩步操作:

  • 根據指定的id刪除文檔
  • 新增一個相同id的文檔

注意:如果根據id刪除時,id不存在,第二步的新增也會執行,也就從修改變成了新增操作了。

語法:

PUT /{索引庫名}/_doc/文檔id
{"字段1": "值1","字段2": "值2",// ... 略
}

示例:

PUT /heima/_doc/1
{"info": "黑馬程序員高級Java講師","email": "zy@itcast.cn","name": {"firstName": "云","lastName": "趙"}
}

由于id為1的文檔已經被刪除,所以第一次執行時,得到的反饋是created

在這里插入圖片描述
所以如果執行第2次時,得到的反饋則是updated
在這里插入圖片描述

4.2.局部修改

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

語法:

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

示例:

POST /heima/_update/1
{"doc": {"email": "ZhaoYun@itcast.cn"}
}

執行結果:
在這里插入圖片描述
在這里插入圖片描述

批處理

批處理采用POST請求,基本語法如下:

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"} }

其中:

  • index代表新增操作
    • _index:指定索引庫名
    • _id指定要操作的文檔id
    • { “field1” : “value1” }:則是要新增的文檔內容
  • delete代表刪除操作
    • _index:指定索引庫名
    • _id指定要操作的文檔id
  • update代表更新操作
    • _index:指定索引庫名
    • _id指定要操作的文檔id
    • { “doc” : {“field2” : “value2”} }:要更新的文檔字段

示例,批量新增:

POST /_bulk
{"index": {"_index":"heima", "_id": "3"}}
{"info": "黑馬程序員C++講師", "email": "ww@itcast.cn", "name":{"firstName": "五", "lastName":"王"}}
{"index": {"_index":"heima", "_id": "4"}}
{"info": "黑馬程序員前端講師", "email": "zhangsan@itcast.cn", "name":{"firstName": "三", "lastName":"張"}}

批量刪除:

POST /_bulk
{"delete":{"_index":"heima", "_id": "3"}}
{"delete":{"_index":"heima", "_id": "4"}}

小結

文檔操作有哪些?

  • 創建文檔:POST /{索引庫名}/_doc/文檔id { json文檔 }
  • 查詢文檔:GET /{索引庫名}/_doc/文檔id
  • 刪除文檔:DELETE /{索引庫名}/_doc/文檔id
  • 修改文檔:
    • 全量修改:PUT /{索引庫名}/_doc/文檔id { json文檔 }
    • 局部修改:POST /{索引庫名}/_update/文檔id { “doc”: {字段}}

Java客戶端操作索引庫

Elasticsearch目前最新版本是8.0,其java客戶端有很大變化。不過大多數企業使用的還是8以下版本,所以我們選擇使用早期的JavaRestClient客戶端來學習。官方文檔地址:Elasticsearch Clients|Elastic

在這里插入圖片描述
然后選擇7.12版本,HighLevelRestClient版本:

在這里插入圖片描述

初始化client

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

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

<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")
));

這里為了單元測試方便,我們創建一個測試類IndexTest,然后將初始化的代碼編寫在@BeforeEach方法中:

package com.hmall.item.es;import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
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 java.io.IOException;public class ElasticSearchTest {private RestHighLevelClient client;@BeforeEachvoid setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.88.130:9200")));}@Testvoid testConnect() {System.out.println(client);}@AfterEachvoid tearDown() throws IOException {this.client.close();}}

1.創建索引庫

由于要實現對商品搜索,所以我們需要將商品添加到Elasticsearch中,不過需要根據搜索業務的需求來設定索引庫結構,而不是一股腦的把MySQL數據寫入Elasticsearch.

1.1.Mapping映射

搜索頁面的效果如圖所示:
在這里插入圖片描述
實現搜索功能需要的字段包括三大部分:

  • 搜索過濾字段
    • 分類
    • 品牌
    • 價格
  • 排序字段
    • 默認:按照更新時間降序排序
    • 銷量
    • 價格
  • 展示字段
    • 商品id:用于點擊后跳轉
    • 圖片地址
    • 是否是廣告推廣商品
    • 名稱
    • 價格
    • 評價數量
    • 銷量
      對應的商品表結構如下,索引庫無關字段已經劃掉:

在這里插入圖片描述
結合數據庫表結構,以上字段對應的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"}}}
}

1.2.創建索引

創建索引庫的API如下:
在這里插入圖片描述

在這里插入圖片描述

代碼分為三步:

  • 1)創建Request對象。
    • 因為是創建索引庫的操作,因此Request是CreateIndexRequest
  • 2)添加請求參數
    • 其實就是Json格式的Mapping映射參數。因為json字符串很長,這里是定義了靜態字符串常量MAPPING_TEMPLATE,讓代碼看起來更加優雅。
  • 3)發送請求
    • client.indices()方法的返回值是IndicesClient類型,封裝了所有與索引庫操作有關的方法。例如創建索引、刪除索引、判斷索引是否存在等

在item-service中的IndexTest測試類中,具體代碼如下:

@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" +"}";

2.刪除索引庫

刪除索引庫的請求非常簡單:

DELETE /hotel

與創建索引庫相比:

  • 請求方式從PUT變為DELTE
  • 請求路徑不變
  • 無請求參數

所以代碼的差異,注意體現在Request對象上。流程如下:

  • 1)創建Request對象。這次是DeleteIndexRequest對象
  • 2)準備參數。這里是無參,因此省略
  • 3)發送請求。改用delete方法

item-service中的IndexTest測試類中,編寫單元測試,實現刪除索引:

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

3.判斷索引庫是否存在

判斷索引庫是否存在,本質就是查詢,對應的請求語句是:

GET /hotel

因此與刪除的Java代碼流程是類似的,流程如下:

  • 1)創建Request對象。這次是GetIndexRequest對象
  • 2)準備參數。這里是無參,直接省略
  • 3)發送請求。改用exists方法
@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 ? "索引庫已經存在!" : "索引庫不存在!");
}

4.總結

JavaRestClient操作elasticsearch的流程基本類似。核心是client.indices()方法來獲取索引庫的操作對象。
索引庫操作的基本步驟:

  • 初始化RestHighLevelClient
  • 創建XxxIndexRequest。XXX是CreateGetDelete
  • 準備請求參數( Create時需要,其它是無參,可以省略)
  • 發送請求。調用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete

5.1.新增文檔

我們需要將數據庫中的商品信息導入elasticsearch中,而不是造假數據了。

5.1.1.實體類

索引庫結構與數據庫結構還存在一些差異,因此我們要定義一個索引庫結構對應的實體。
在hm-service模塊的com.hmall.item.domain.dto包中定義一個新的DTO:

package com.hmall.item.domain.po;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.time.LocalDateTime;@Data
@ApiModel(description = "索引庫實體")
public class ItemDoc{@ApiModelProperty("商品id")private String id;@ApiModelProperty("商品名稱")private String name;@ApiModelProperty("價格(分)")private Integer price;@ApiModelProperty("商品圖片")private String image;@ApiModelProperty("類目名稱")private String category;@ApiModelProperty("品牌名稱")private String brand;@ApiModelProperty("銷量")private Integer sold;@ApiModelProperty("評論數")private Integer commentCount;@ApiModelProperty("是否是推廣廣告,true/false")private Boolean isAD;@ApiModelProperty("更新時間")private LocalDateTime updateTime;
}

5.1.2.API語法

新增文檔的請求語法如下:

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

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

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

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

5.1.3.完整代碼

我們導入商品數據,除了參考API模板“三步走”以外,還需要做幾點準備工作:

  • 商品數據來自于數據庫,我們需要先查詢出來,得到Item對象
  • Item對象需要轉為ItemDoc對象
  • ItemDTO需要序列化為json格式

因此,代碼整體步驟如下:

  • 1)根據id查詢商品數據Item
  • 2)將Item封裝為ItemDoc
  • 3)將ItemDoc序列化為JSON
  • 4)創建IndexRequest,指定索引庫名和id
  • 5)準備請求參數,也就是JSON文檔
  • 6)發送請求

在item-service的DocumentTest測試類中,編寫單元測試:

package com.heima.item.es;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.hmall.item.ItemApplication;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.po.ItemDoc;
import com.hmall.item.service.IItemService;
import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
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;@SpringBootTest(classes = ItemApplication.class,properties = "spring.profiles.active=local")
public class DocumentTest {private RestHighLevelClient client;@Autowiredprivate IItemService itemService;@BeforeEachvoid setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.88.130:9200")));}@Testvoid testConnect() {System.out.println(client);}@AfterEachvoid tearDown() throws IOException {this.client.close();}@Testvoid 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 /items/_doc/100002644680

在這里插入圖片描述

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

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

相關文章

安裝OpenJDK1.8 17 (macos M芯片)

安裝OpenJDK 1.8 下載完后&#xff0c;解壓&#xff0c;打開 環境變量的配置文件即可 vim ~/.zshrc #export JAVA_HOME/Users/xxxxx/jdk-21.jdk/Contents/Home #export JAVA_HOME/Users/xxxxx/jdk-17.jdk/Contents/Home #export JAVA_HOME/Users/xxxxx/jdk-11.jdk/Contents…

斷言與反射——以golang為例

斷言 x.(T) 檢查x的動態類型是否是T&#xff0c;其中x必須是接口值。 簡單使用 func main() {var x interface{}x 100value1, ok : x.(int)if ok {fmt.Println(value1)}value2, ok : x.(string)if ok {//未打印fmt.Println(value2)} }需要注意如果不接受第二個參數就是OK,這…

Java設計模式:系統性解析與核心模式

一、設計模式三大分類總覽 創建型模式&#xff08;5種&#xff09; 核心目標&#xff1a;對象創建的優化與解耦 單例模式&#xff08;Singleton&#xff09; 工廠模式&#xff08;Factory&#xff09; 抽象工廠模式&#xff08;Abstract Factory&#xff09; 建造者模式&#…

Elasticsearch 向量數據庫,原生支持 Google Cloud Vertex AI 平臺

作者&#xff1a;來自 Elastic Valerio Arvizzigno Elasticsearch 將作為第一個第三方原生語義對齊引擎&#xff0c;支持 Google Cloud 的 Vertex AI 平臺和 Google 的 Gemini 模型。這使得聯合用戶能夠基于企業數據構建完全可定制的生成式 AI 體驗&#xff0c;并借助 Elastics…

408 計算機網絡 知識點記憶(7)

前言 本文基于王道考研課程與湖科大計算機網絡課程教學內容&#xff0c;系統梳理核心知識記憶點和框架&#xff0c;既為個人復習沉淀思考&#xff0c;亦希望能與同行者互助共進。&#xff08;PS&#xff1a;后續將持續迭代優化細節&#xff09; 往期內容 408 計算機網絡 知識…

10-MySQL-性能優化思路

1、優化思路 當我們發現了一個慢SQL的問題的時候,需要做性能優化,一般我們是為了提高SQL查詢更快,一個查詢的流程由下圖的各環節組成,每個環節都會消耗時間,要減少消耗時候需要從各個環節都分析一遍。 2 連接配置優化 第一個環節是客戶端連接到服務端,這塊可能會出現服務…

Docker:安裝與部署 Nacos 的技術指南

1、簡述 Nacos(Dynamic Naming and Configuration Service)是阿里巴巴開源的一個動態服務發現、配置管理和服務治理的綜合解決方案,適用于微服務架構。 Nacos 主要功能: 服務發現與注冊:支持 Dubbo、Spring Cloud 等主流微服務框架的服務發現與注冊。動態配置管理:支持…

【非機動車檢測】用YOLOv8實現非機動車及駕駛人佩戴安全帽檢測

非機動車及駕駛人佩戴安全帽檢測任務的意義主要包括以下幾點&#xff1a; 保障行車安全&#xff1a;非機動車包括自行車、電動車等&#xff0c;佩戴安全帽能夠有效保護騎車人頭部&#xff0c;減少因交通事故造成的頭部傷害風險&#xff0c;提高行車安全系數。 符合交通法規&am…

壹起航:15年深耕互聯網營銷,助力中國工廠出海獲客

在全球化浪潮下&#xff0c;越來越多的中國工廠渴望拓展海外市場&#xff0c;但面臨品牌建立、穩定詢盤獲取及營銷成本降低等多重挑戰。壹起航憑借15年的豐富經驗&#xff0c;整合外貿建站、SEO優化及海外短視頻營銷&#xff0c;為中國工廠提供一站式出海解決方案。 一、外貿獨…

Emacs 折騰日記(二十)——修改emacs的一些默認行為

上一篇我們完成了emacs輸入法的配置以及將emacs配置成了使用vim的操作方式。但是emacs目前有些默認行為我不太喜歡&#xff0c;這節我們一起來修改它 備份設置 我們打開emacs的配置文件所在路徑&#xff0c;發現有大量的~結尾的文件&#xff0c;這是emacs的備份文件。這里&am…

聊透多線程編程-線程基礎-4.C# Thread 子線程執行完成后通知主線程執行特定動作

在多線程編程中&#xff0c;線程之間的同步和通信是一個常見的需求。例如&#xff0c;我們可能需要一個子線程完成某些任務后通知主線程&#xff0c;并由主線程執行特定的動作。本文將基于一個示例程序&#xff0c;詳細講解如何使用 AutoResetEvent 來實現這種場景。 示例代碼…

【網絡安全 | 項目開發】Web 安全響應頭掃描器(提升網站安全性)

原創項目,未經許可,不得轉載。 文章目錄 項目簡介工作流程示例輸出技術棧項目代碼使用說明項目簡介 安全響應頭是防止常見 Web 攻擊(如點擊劫持、跨站腳本攻擊等)的有效防線,因此合理的配置這些頭部信息對任何網站的安全至關重要。 Web 安全響應頭掃描器(Security Head…

使用libcurl編寫爬蟲程序指南

用戶想知道用Curl庫編寫的爬蟲程序是什么樣的。首先&#xff0c;我需要明確Curl本身是一個命令行工具和庫&#xff0c;用于傳輸數據&#xff0c;支持多種協議。而用戶提到的“Curl庫”可能指的是libcurl&#xff0c;這是一個客戶端URL傳輸庫&#xff0c;可以用在C、C等編程語言…

使用pip3安裝PyTorch與PyG,實現NVIDIA CUDA GPU加速

使用python3的pip3命令安裝python依賴庫。 # python3 -V Python 3.12.3 # # pip3 -V pip 25.0.1 from /root/.pyenv/versions/3.12.3/lib/python3.12/site-packages/pip (python 3.12)Usage: pip3 install [options] <package> ...pip3 install [options] -r <re…

五種常用的web加密算法

文章目錄 五種常用Web加密算法實戰及原理詳解1. AES (高級加密標準)原理詳解應用場景實戰代碼&#xff08;Node.js&#xff09; 2. RSA (非對稱加密)原理詳解應用場景實戰代碼&#xff08;Node.js&#xff09; 3. SHA-256 (安全哈希算法)原理詳解應用場景實戰代碼&#xff08;瀏…

深入解析 C++ 設計模式:原理、實現與應用

一、引言 在 C 編程的廣袤領域中&#xff0c;設計模式猶如閃耀的燈塔&#xff0c;為開發者指引著構建高效、可維護軟件系統的方向。設計模式并非神秘莫測的代碼魔法&#xff0c;實際上&#xff0c;我們在日常編程中或許早已與之打過交道。簡單來說&#xff0c;設計模式常常借助…

Python刷題筆記

Python刷題筆記 1、輸出格式化 第一種格式化的輸出&#xff1a; name "jack" age 17 salary 20031.8752 print("你的名字是&#xff1a;%s,今年 %d 歲,工資 %7.2f" % (name,age,salary) ) --------------------------------------- 你的名字是&#…

【Kubernetes】Kubernetes 如何進行日志管理?Fluentd / Loki / ELK 適用于什么場景?

由于 Kubernetes 運行在容器化的環境中&#xff0c;應用程序和系統日志通常分布在多個容器和節點上&#xff0c;傳統的日志管理方法&#xff08;例如直接訪問每個節點的日志文件&#xff09;在 Kubernetes 中不適用。 因此&#xff0c;Kubernetes 引入了集中式日志管理方案&am…

Ansible(8)——循環與條件任務

目錄 一、循環迭代任務&#xff1a; 1、簡單循環&#xff1a; 2、循環字典列表&#xff1a; 3、Ansible 2.5 之前的循環關鍵字&#xff1a; 4、在循環中使用 register 變量&#xff1a; 二、條件任務&#xff1a; 1、使用條件句的常見場景&#xff1a; 2、條件任務語法…

adb|scrcpy的安裝和配置方法|手機投屏電腦|手機聲音投電腦|adb連接模擬器或手機

adb|scrcpy的安裝和配置方法手機投屏電腦|手機聲音投電腦|adb連接模擬器或手機或電視 引言 在數字設備交織的現代生活中&#xff0c;adb&#xff08;Android Debug Bridge&#xff09;與 scrcpy 宛如隱匿的強大工具&#xff0c;極大地拓展了我們操控手機、模擬器乃至智能電視等…