重慶廣告網(wǎng)站推廣seo結(jié)算系統(tǒng)
Elasticsearch 是一款基于 Lucene 庫(kù)構(gòu)建的開(kāi)源、分布式、RESTful 風(fēng)格的搜索引擎和分析引擎,具有強(qiáng)大的全文搜索、數(shù)據(jù)分析、機(jī)器學(xué)習(xí)等功能,廣泛應(yīng)用于日志分析、實(shí)時(shí)數(shù)據(jù)分析、全文檢索等場(chǎng)景。
核心概念
- 索引(Index):類似于傳統(tǒng)數(shù)據(jù)庫(kù)中的數(shù)據(jù)庫(kù),是存儲(chǔ)數(shù)據(jù)的邏輯容器。一個(gè)索引可以包含多個(gè)類型的數(shù)據(jù),每個(gè)索引都有一個(gè)唯一的名稱用于標(biāo)識(shí)。
- 類型(Type):在早期版本中,一個(gè)索引可以有多個(gè)類型,用來(lái)區(qū)分不同類型的數(shù)據(jù),但在 7.x 及以上版本中,一個(gè)索引只能有一個(gè)類型,且默認(rèn)類型為“_doc”。
- 文檔(Document):是 Elasticsearch 中存儲(chǔ)和檢索的基本數(shù)據(jù)單元,以 JSON 格式表示。每個(gè)文檔都有一個(gè)唯一的 ID,用于在索引中定位和操作文檔。
- 字段(Field):是文檔中的一個(gè)屬性或鍵值對(duì),用于存儲(chǔ)具體的數(shù)據(jù)內(nèi)容,如姓名、年齡、價(jià)格等。字段有不同的數(shù)據(jù)類型,如文本、數(shù)字、日期等,不同的數(shù)據(jù)類型決定了字段的存儲(chǔ)和檢索方式。
主要特點(diǎn)
- 高性能全文搜索:基于 Lucene 的倒排索引技術(shù),能夠快速地對(duì)文本數(shù)據(jù)進(jìn)行全文搜索。它會(huì)將文本數(shù)據(jù)拆分成單詞或詞匯,建立索引,當(dāng)進(jìn)行搜索時(shí),通過(guò)查找索引快速定位到包含搜索關(guān)鍵詞的文檔,大大提高了搜索效率。
- 分布式架構(gòu):可以部署在多個(gè)節(jié)點(diǎn)上,形成一個(gè)分布式集群。數(shù)據(jù)會(huì)被自動(dòng)分片存儲(chǔ)在不同的節(jié)點(diǎn)上,當(dāng)一個(gè)節(jié)點(diǎn)出現(xiàn)問(wèn)題時(shí),其他節(jié)點(diǎn)可以繼續(xù)提供服務(wù),保證了系統(tǒng)的高可用性和數(shù)據(jù)的可靠性。同時(shí),分布式架構(gòu)也使得 Elasticsearch 能夠處理海量的數(shù)據(jù)和高并發(fā)的請(qǐng)求。
- 易于擴(kuò)展:隨著數(shù)據(jù)量和訪問(wèn)量的增加,可以通過(guò)簡(jiǎn)單地增加節(jié)點(diǎn)來(lái)水平擴(kuò)展集群。新加入的節(jié)點(diǎn)會(huì)自動(dòng)參與數(shù)據(jù)的存儲(chǔ)和查詢工作,無(wú)需對(duì)現(xiàn)有系統(tǒng)進(jìn)行復(fù)雜的改造,能夠靈活地應(yīng)對(duì)業(yè)務(wù)的增長(zhǎng)。
- RESTful API:提供了基于 HTTP 協(xié)議的 RESTful 風(fēng)格的 API 接口,方便開(kāi)發(fā)者使用各種編程語(yǔ)言進(jìn)行集成和開(kāi)發(fā)。通過(guò)簡(jiǎn)單的 HTTP 請(qǐng)求,就可以完成數(shù)據(jù)的增刪改查、索引管理、查詢分析等各種操作,降低了開(kāi)發(fā)難度和成本。
- 多租戶支持:在 Elasticsearch 集群中,可以創(chuàng)建多個(gè)索引,每個(gè)索引可以視為一個(gè)獨(dú)立的“租戶”,不同租戶之間的數(shù)據(jù)相互隔離。這使得 Elasticsearch 能夠在一個(gè)集群中同時(shí)為多個(gè)應(yīng)用程序或用戶提供服務(wù),提高了資源利用率。
- 強(qiáng)大的聚合分析功能:除了基本的搜索功能,還提供了豐富的聚合分析功能,如統(tǒng)計(jì)、分組、排序、時(shí)間序列分析等??梢詫?duì)搜索結(jié)果進(jìn)行進(jìn)一步的數(shù)據(jù)挖掘和分析,幫助用戶快速獲取數(shù)據(jù)的統(tǒng)計(jì)信息和趨勢(shì),為決策提供支持。
常見(jiàn)應(yīng)用場(chǎng)景
- 日志分析:能夠高效地收集、存儲(chǔ)和分析各種日志數(shù)據(jù),如服務(wù)器日志、應(yīng)用程序日志、網(wǎng)絡(luò)設(shè)備日志等。通過(guò)對(duì)日志數(shù)據(jù)的搜索、過(guò)濾、聚合分析,可以快速定位系統(tǒng)故障、性能瓶頸、安全問(wèn)題等,為運(yùn)維人員提供有力的工具。
- 實(shí)時(shí)數(shù)據(jù)分析:適用于需要實(shí)時(shí)處理和分析大量數(shù)據(jù)的場(chǎng)景,如金融交易監(jiān)控、社交媒體數(shù)據(jù)監(jiān)測(cè)、物聯(lián)網(wǎng)設(shè)備數(shù)據(jù)處理等。Elasticsearch 可以實(shí)時(shí)地接收數(shù)據(jù),快速地進(jìn)行查詢和分析,及時(shí)發(fā)現(xiàn)異常情況并做出響應(yīng)。
- 全文檢索:為各種需要全文檢索功能的應(yīng)用程序提供支持,如電子商務(wù)網(wǎng)站的商品搜索、知識(shí)管理系統(tǒng)的內(nèi)容檢索、新聞網(wǎng)站的新聞搜索等。能夠根據(jù)用戶的輸入關(guān)鍵詞,快速地在海量文本數(shù)據(jù)中找到匹配的結(jié)果,并按照相關(guān)性進(jìn)行排序,提升用戶體驗(yàn)。
- 機(jī)器學(xué)習(xí):結(jié)合 Elasticsearch 的機(jī)器學(xué)習(xí)功能,可以對(duì)數(shù)據(jù)進(jìn)行自動(dòng)分析和建模,實(shí)現(xiàn)異常檢測(cè)、預(yù)測(cè)分析等高級(jí)功能。例如,在網(wǎng)絡(luò)安全領(lǐng)域,通過(guò)機(jī)器學(xué)習(xí)算法對(duì)網(wǎng)絡(luò)流量數(shù)據(jù)進(jìn)行分析,自動(dòng)識(shí)別潛在的攻擊行為;在電商領(lǐng)域,預(yù)測(cè)用戶的購(gòu)買行為和需求。
架構(gòu)組件
- 節(jié)點(diǎn)(Node):是 Elasticsearch 集群中的一個(gè)服務(wù)器實(shí)例,承擔(dān)著數(shù)據(jù)存儲(chǔ)、查詢處理、集群管理等任務(wù)。節(jié)點(diǎn)之間通過(guò)網(wǎng)絡(luò)進(jìn)行通信和協(xié)作,共同構(gòu)成一個(gè)完整的 Elasticsearch 集群。
- 集群(Cluster):由一個(gè)或多個(gè)節(jié)點(diǎn)組成,通過(guò)配置集群名稱來(lái)標(biāo)識(shí)。集群負(fù)責(zé)管理節(jié)點(diǎn)、分配分片、處理請(qǐng)求等,保證數(shù)據(jù)的一致性和高可用性。集群中的主節(jié)點(diǎn)(Master Node)負(fù)責(zé)集群級(jí)別的操作,如創(chuàng)建索引、分配分片、節(jié)點(diǎn)發(fā)現(xiàn)等,數(shù)據(jù)節(jié)點(diǎn)(Data Node)主要負(fù)責(zé)存儲(chǔ)數(shù)據(jù)和執(zhí)行查詢操作。
- 分片(Shard):為了提高數(shù)據(jù)的存儲(chǔ)能力和查詢性能,索引會(huì)被分割成多個(gè)分片,每個(gè)分片是一個(gè)獨(dú)立的 Lucene 索引。分片可以分布在不同的節(jié)點(diǎn)上,當(dāng)進(jìn)行查詢時(shí),查詢請(qǐng)求會(huì)被分發(fā)到各個(gè)分片上并行執(zhí)行,然后將結(jié)果匯總返回。分片的數(shù)量在索引創(chuàng)建時(shí)確定,可以根據(jù)數(shù)據(jù)量和查詢需求進(jìn)行合理配置。
- 副本(Replica):是分片的副本,用于提高數(shù)據(jù)的可靠性和查詢性能。當(dāng)一個(gè)分片出現(xiàn)故障時(shí),副本可以接管其查詢請(qǐng)求,保證服務(wù)的可用性。同時(shí),副本也可以分擔(dān)查詢負(fù)載,提高查詢的并發(fā)處理能力。副本的數(shù)量可以根據(jù)集群的節(jié)點(diǎn)數(shù)量和可靠性要求進(jìn)行配置。
數(shù)據(jù)寫入與查詢流程
- 數(shù)據(jù)寫入流程:
- 客戶端發(fā)送寫入請(qǐng)求:用戶或應(yīng)用程序通過(guò) Elasticsearch 的 RESTful API 向集群發(fā)送數(shù)據(jù)寫入請(qǐng)求,請(qǐng)求中包含要寫入的索引名稱、文檔數(shù)據(jù)等信息。
- 主節(jié)點(diǎn)路由請(qǐng)求:主節(jié)點(diǎn)接收到請(qǐng)求后,根據(jù)索引的分片策略,將寫入請(qǐng)求路由到對(duì)應(yīng)的主分片所在的節(jié)點(diǎn)。
- 主分片寫入數(shù)據(jù):主分片節(jié)點(diǎn)接收到請(qǐng)求后,將數(shù)據(jù)寫入本地的分片中,并記錄操作日志。寫入成功后,會(huì)將操作日志發(fā)送給對(duì)應(yīng)的副本分片節(jié)點(diǎn)。
- 副本分片同步數(shù)據(jù):副本分片節(jié)點(diǎn)接收到操作日志后,會(huì)根據(jù)日志內(nèi)容將數(shù)據(jù)同步到本地的副本分片中。當(dāng)所有副本分片都成功同步數(shù)據(jù)后,主分片節(jié)點(diǎn)會(huì)向客戶端返回寫入成功的響應(yīng)。
- 數(shù)據(jù)查詢流程:
- 客戶端發(fā)送查詢請(qǐng)求:用戶或應(yīng)用程序通過(guò) RESTful API 向集群發(fā)送查詢請(qǐng)求,請(qǐng)求中包含查詢條件、索引名稱等信息。
- 主節(jié)點(diǎn)分發(fā)查詢請(qǐng)求:主節(jié)點(diǎn)接收到查詢請(qǐng)求后,根據(jù)索引的分片分布情況,將查詢請(qǐng)求分發(fā)到所有相關(guān)的分片所在的節(jié)點(diǎn)。
- 分片節(jié)點(diǎn)執(zhí)行查詢:各個(gè)分片節(jié)點(diǎn)接收到查詢請(qǐng)求后,在本地的分片中執(zhí)行查詢操作,根據(jù)查詢條件檢索匹配的文檔,并將查詢結(jié)果返回給主節(jié)點(diǎn)。
- 主節(jié)點(diǎn)匯總結(jié)果:主節(jié)點(diǎn)接收到各個(gè)分片節(jié)點(diǎn)返回的查詢結(jié)果后,對(duì)結(jié)果進(jìn)行匯總和排序等處理,然后將最終的查詢結(jié)果返回給客戶端。
Elasticsearch基礎(chǔ)概念
Index:索引(index),就是文檔的集合,類似數(shù)據(jù)庫(kù)的表(table)
Document:文檔(Document),就是一條條的數(shù)據(jù),類似數(shù)據(jù)庫(kù)中的行(Row),文檔都是JSON格式
Field:字段(Field),就是JSON文檔中的字段,類似數(shù)據(jù)庫(kù)中的列(Column)
Mapping:Mapping(映射)是索引中文檔的約束,例如字段類型約束。類似數(shù)據(jù)庫(kù)的表結(jié)構(gòu)(Schema)
DSL:DSL是elasticsearch提供的JSON風(fēng)格的請(qǐng)求語(yǔ)句,用來(lái)操作elasticsearch,實(shí)現(xiàn)CRUD
倒排索引
正向索引
- 文檔 ID:用于唯一標(biāo)識(shí)每個(gè)文檔,類似數(shù)據(jù)庫(kù)表中的主鍵,有了它就能精準(zhǔn)定位到特定的某一文檔。
- 索引項(xiàng):跟在文檔 ID 后面,包含了文檔中的各類關(guān)鍵元素,比如文本里的詞匯、數(shù)據(jù)記錄的屬性值等,有的還會(huì)附上這些元素在文檔中的具體位置信息。
倒排索引
-
文檔(Document):用來(lái)搜索的數(shù)據(jù),其中的每一條數(shù)據(jù)就是一個(gè)文檔。例如一個(gè)網(wǎng)頁(yè)、一個(gè)商品信息。
-
詞條(Term):對(duì)文檔數(shù)據(jù)或用戶搜索數(shù)據(jù),利用某種算法分詞,得到的具備含義的詞語(yǔ)就是詞條。例如:我是中國(guó)人,就可以分為:我、是、中國(guó)人、中國(guó)、國(guó)人這樣的幾個(gè)詞條。
對(duì)比
正向索引的表結(jié)構(gòu)
id(索引) | title | price |
---|---|---|
1 | 小米手機(jī) | 3499 |
2 | 華為手機(jī) | 4999 |
3 | 華為小米充電器 | 49 |
4 | 小米手環(huán) | 49 |
搜索流程:
-
1)如檢查到搜索條件為
like '%手機(jī)%'
,需要找到title
中包含手機(jī)
的數(shù)據(jù) -
2)逐條遍歷每行數(shù)據(jù)(每個(gè)葉子節(jié)點(diǎn)),比如第1次拿到
id
為1的數(shù)據(jù) -
3)判斷數(shù)據(jù)中的
title
字段值是否符合條件 -
4)如果符合則放入結(jié)果集,不符合則丟棄
-
5)回到步驟1
倒排索引的表結(jié)構(gòu)
詞條(索引) | 文檔id |
---|---|
小米 | 1,3,4 |
手機(jī) | 1,2 |
華為 | 2,3 |
充電器 | 3 |
手環(huán) | 4 |
?搜索流程:
1)如用戶輸入條件"華為手機(jī)"
進(jìn)行搜索。
2)對(duì)用戶輸入條件分詞,得到詞條:華為
、手機(jī)
。
3)拿著詞條在倒排索引中查找(由于詞條有索引,查詢效率很高),即可得到包含詞條的文檔id:1、2、3
。
4)拿著文檔id
到正向索引中查找具體文檔即可(由于id
也有索引,查詢效率也很高)。
正向索引:
-
優(yōu)點(diǎn):
-
可以給多個(gè)字段創(chuàng)建索引
-
根據(jù)索引字段搜索、排序速度非???/p>
-
-
缺點(diǎn):
-
根據(jù)非索引字段,或者索引字段中的部分詞條查找時(shí),只能全表掃描。
-
倒排索引:
-
優(yōu)點(diǎn):
-
根據(jù)詞條搜索、模糊搜索時(shí),速度非???/p>
-
-
缺點(diǎn):
-
只能給詞條創(chuàng)建索引,而不是字段
-
無(wú)法根據(jù)字段做排序
-
安裝Elasticsearch
1.使用docker安裝單機(jī)版的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 es-net \-p 9200:9200 \-p 9300:9300 \--restart=always \elasticsearch:7.12.1
代碼解讀:
-d:讓容器在后臺(tái)運(yùn)行
--name:指定創(chuàng)建的容器名稱
-e:設(shè)置容器內(nèi)的環(huán)境變量
-v:將容器內(nèi)的目錄掛載到外部的卷上
--privileged:以特權(quán)模式運(yùn)行容器
--network:將容器連接到名為 es-net?的 Docker 網(wǎng)絡(luò),在我們搭建服務(wù)器的時(shí)候可以創(chuàng)建一個(gè)docker網(wǎng)絡(luò),將要互相通信的放在這一個(gè)網(wǎng)絡(luò)里面。注意:這里需要先用docker network create創(chuàng)建一個(gè)docker網(wǎng)絡(luò)這里才能指定
-p:將容器的端口映射到主機(jī)的端口
--restart=always:設(shè)置容器自啟動(dòng)
?elasticsearch:7.12.1:要運(yùn)行的 Docker 鏡像名稱和標(biāo)簽,如果我們指定這個(gè)鏡像本地沒(méi)有這個(gè)版本就會(huì)進(jìn)行下載。注意:這里我們采用的是elasticsearch的7.12.1版本,由于8以上版本的JavaAPI變化很大,在企業(yè)中應(yīng)用并不廣泛,企業(yè)中應(yīng)用較多的還是8以下的版本。
2.防火墻開(kāi)放端口
#1.開(kāi)放es端口
firewall-cmd --zone=public --add-port=9200/tcp --add-port=9300/tcp --permanent
#2.重新加載防火墻配置
firewall-cmd --reload
也可以關(guān)閉防火墻
systemctl stop firewalld
3.訪問(wèn)9200端口驗(yàn)證es是否啟動(dòng)成功
地址格式:主機(jī)IP:9200
IK分詞器
Elasticsearch的關(guān)鍵就是倒排索引,而倒排索引依賴于對(duì)文檔內(nèi)容的分詞,而分詞則需要高效、精準(zhǔn)的分詞算法,IK分詞器就是這樣一個(gè)中文分詞算法。
安裝
方法一:在線安裝
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
方法二:離線安裝
首先,查看之前安裝的es容器的plugins數(shù)據(jù)卷目錄:
docker volume inspect es-plugins
結(jié)果如下:?
進(jìn)入/var/lib/docker/volumes/es-plugins/_data目錄,將我們本地的ik上傳到這個(gè)目錄下
?重啟es容器
docker restart es
使用
IK分詞器包含兩種模式:
ik_smart
:智能語(yǔ)義切分
示例:
POST /_analyze
{"analyzer": "ik_smart","text": "我是一個(gè)程序員"
}
結(jié)果:
{"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" : "一個(gè)","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 2},{"token" : "程序員","start_offset" : 4,"end_offset" : 7,"type" : "CN_WORD","position" : 3}]
}
ik_max_word
:最細(xì)粒度切分
示例:
POST /_analyze
{"analyzer": "ik_max_word","text": "我是一個(gè)程序員"
}
結(jié)果:?
{"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" : "一個(gè)","start_offset" : 2,"end_offset" : 4,"type" : "CN_WORD","position" : 2},{"token" : "一","start_offset" : 2,"end_offset" : 3,"type" : "TYPE_CNUM","position" : 3},{"token" : "個(gè)","start_offset" : 3,"end_offset" : 4,"type" : "COUNT","position" : 4},{"token" : "程序員","start_offset" : 4,"end_offset" : 7,"type" : "CN_WORD","position" : 5},{"token" : "程序","start_offset" : 4,"end_offset" : 6,"type" : "CN_WORD","position" : 6},{"token" : "員","start_offset" : 6,"end_offset" : 7,"type" : "CN_CHAR","position" : 7}]
}
?拓展詞典
隨著互聯(lián)網(wǎng)的發(fā)展,“造詞運(yùn)動(dòng)”也越發(fā)的頻繁。出現(xiàn)了很多新的詞語(yǔ),在原有的詞匯列表中并不存在,如:“逆天、依托答辯、我了個(gè)豆”
POST /_analyze
{"analyzer": "ik_max_word","text": "逆天、依托答辯、我了個(gè)豆"
}
結(jié)果:
{"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" : 3,"end_offset" : 5,"type" : "CN_WORD","position" : 2},{"token" : "答辯","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 3},{"token" : "我","start_offset" : 8,"end_offset" : 9,"type" : "CN_CHAR","position" : 4},{"token" : "了","start_offset" : 9,"end_offset" : 10,"type" : "CN_CHAR","position" : 5},{"token" : "個(gè)","start_offset" : 10,"end_offset" : 11,"type" : "CN_CHAR","position" : 6},{"token" : "豆","start_offset" : 11,"end_offset" : 12,"type" : "CN_CHAR","position" : 7}]
}
可以看到,逆天和我了個(gè)豆都無(wú)法正確分詞。
所以要想正確分詞,IK分詞器的詞庫(kù)也需要不斷的更新,IK分詞器提供了擴(kuò)展詞匯的功能。
1)打開(kāi)IK分詞器config目錄:
注意:如果采用在線安裝的通過(guò),默認(rèn)是沒(méi)有config目錄的,可以去網(wǎng)上找一些詞庫(kù),讓后創(chuàng)建一個(gè)config文件目錄放在config目錄下
2)在IKAnalyzer.cfg.xml配置文件內(nèi)容添加:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 擴(kuò)展配置</comment><!--可以在這里配置自己的擴(kuò)展字典 --><entry key="ext_dict">ext.dic</entry>
</properties>
3)新建ext.dic文件,用記事本或者其他編輯器打開(kāi)ext.dic文件,然后添加自己想要的詞語(yǔ)即可
4)重啟elasticsearch
docker restart es# 查看 日志
docker logs -f elasticsearch
5.重啟之后再次執(zhí)行之前的命令,可以正確分詞了
{"tokens" : [{"token" : "逆天","start_offset" : 0,"end_offset" : 2,"type" : "CN_WORD","position" : 0},{"token" : "依托答辯","start_offset" : 3,"end_offset" : 7,"type" : "CN_WORD","position" : 1},{"token" : "依托","start_offset" : 3,"end_offset" : 5,"type" : "CN_WORD","position" : 2},{"token" : "答辯","start_offset" : 5,"end_offset" : 7,"type" : "CN_WORD","position" : 3},{"token" : "我了個(gè)豆","start_offset" : 8,"end_offset" : 12,"type" : "CN_WORD","position" : 4}]
}
還可以在IKAnalyzer.cfg.xml加上如下配置:實(shí)現(xiàn)更多功能
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 擴(kuò)展配置</comment><!--用戶可以在這里配置自己的擴(kuò)展字典 --><entry key="ext_dict">ext.dic</entry><!--用戶可以在這里配置自己的擴(kuò)展停止詞字典--><entry key="ext_stopwords">stopword.dic</entry><!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 --><!-- <entry key="remote_ext_dict">words_location</entry> --><!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
RESTAPI使用
ES官方提供了各種不同語(yǔ)言的客戶端,用來(lái)操作ES。這些客戶端的本質(zhì)就是組裝DSL語(yǔ)句,通過(guò)http請(qǐng)求發(fā)送給ES。
官方文檔地址:
Elasticsearch Clients | Elastic
由于ES目前最新版本是8.8,提供了全新版本的客戶端,老版本的客戶端已經(jīng)被標(biāo)記為過(guò)時(shí)。而我們采用的是7.12版本,因此只能使用老版本客戶端:
然后選擇7.12版本,HighLevelRestClient版本:
1.引入es
的RestHighLevelClient
依賴:
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version>
</dependency>
2.初始化RestHighLevelClient:
public class IndexTest {private RestHighLevelClient client;@BeforeEachvoid setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")//es服務(wù)ip地址:端口號(hào)));}@Testvoid testConnect() {System.out.println(client);//執(zhí)行不好錯(cuò)就行了}@AfterEachvoid tearDown() throws IOException {this.client.close();}
}
3.索引庫(kù)相關(guān)操作:
public class ElasticIndexTest {private static final String MAPPING_TEMPLATE = """{"mappings": {"properties": {"id": {"type": "keyword"},"name": {"type": "text","analyzer": "ik_smart"},"price": {"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"}}}}""";//JDK15新特性:三引號(hào)private RestHighLevelClient client;//創(chuàng)建@Testvoid testCreateIndex() throws IOException {//準(zhǔn)備request對(duì)象CreateIndexRequest request = new CreateIndexRequest("items");//準(zhǔn)備請(qǐng)求參數(shù)request.source(MAPPING_TEMPLATE, XContentType.JSON);//發(fā)送請(qǐng)求client.indices().create(request, RequestOptions.DEFAULT);}//判斷是否存在@Testvoid testExistsndex() throws IOException {//準(zhǔn)備request對(duì)象GetIndexRequest request = new GetIndexRequest("items");//發(fā)送請(qǐng)求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println("exists = " + exists);}//刪除@Testvoid testDeleteIndex() throws IOException {//準(zhǔn)備request對(duì)象DeleteIndexRequest request = new DeleteIndexRequest("items");//發(fā)送請(qǐng)求client.indices().delete(request, RequestOptions.DEFAULT);}@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}
4.文檔相關(guān)操作:
package com.hmall.item.es;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.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(properties = "spring.profiles.active=local")
public class ElasticDocumentTest {private RestHighLevelClient client;@Autowiredprivate IItemService itemService;@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}//創(chuàng)建文檔@Testvoid createDoc() throws IOException {//準(zhǔn)備文檔數(shù)據(jù)//1.查詢數(shù)據(jù)Item item = itemService.getById(577967L);//2.把數(shù)據(jù)庫(kù)數(shù)據(jù)轉(zhuǎn)成文檔數(shù)據(jù)ItemDoc itemDoc = BeanUtil.copyProperties(item, ItemDoc.class);//準(zhǔn)備request對(duì)象IndexRequest request = new IndexRequest("items").id(itemDoc.getId());//構(gòu)建請(qǐng)求參數(shù)request.source(JSONUtil.toJsonStr(itemDoc), XContentType.JSON);//發(fā)送請(qǐng)求client.index(request, RequestOptions.DEFAULT);}//獲取文檔數(shù)據(jù)@Testvoid testGetDoc() throws IOException {//準(zhǔn)備request對(duì)象GetRequest request = new GetRequest("items", "577967");//發(fā)送請(qǐng)求GetResponse response = client.get(request, RequestOptions.DEFAULT);//獲取響應(yīng)結(jié)果中的sourceString json = response.getSourceAsString();//轉(zhuǎn)成java對(duì)象ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);System.out.println("itemDoc = " + itemDoc);}//刪除文檔@Testvoid testDelDoc() throws IOException {//準(zhǔn)備request對(duì)象DeleteRequest request = new DeleteRequest("items", "577967");//發(fā)送請(qǐng)求client.delete(request, RequestOptions.DEFAULT);}//修改文檔數(shù)據(jù)@Testvoid testUpdateDoc() throws IOException {//準(zhǔn)備request對(duì)象UpdateRequest request = new UpdateRequest("items", "577967");request.doc("price", 29900);//發(fā)送請(qǐng)求client.update(request, RequestOptions.DEFAULT);}//批量操作文檔:新增@Testvoid testBulkDoc() throws IOException {int pageNo = 1, pageSize = 500;while (true) {Page<Item> page = itemService.lambdaQuery().eq(Item::getStatus, 1).page(Page.of(pageNo, pageSize));List<Item> records = page.getRecords();if (records == null || records.isEmpty()) {return;}//準(zhǔn)備BulkRequest對(duì)象BulkRequest request = new BulkRequest();for (Item item : records) {//添加批量提交的請(qǐng)求request.add(new IndexRequest("items").id(item.getId().toString()).source(JSONUtil.toJsonStr(BeanUtil.copyProperties(item, ItemDoc.class)), XContentType.JSON));}//提交請(qǐng)求client.bulk(request, RequestOptions.DEFAULT);pageNo++;}}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}
5.查詢數(shù)據(jù)相關(guān)操作:
public class ElasticSearchTest {private RestHighLevelClient client;private static void parseResponseResult(SearchResponse response) {//得到命中的數(shù)據(jù)SearchHits hits = response.getHits();long total = hits.getTotalHits().value;System.out.println("total = " + total);for (SearchHit hit : hits) {//解析數(shù)據(jù)String json = hit.getSourceAsString();//封裝itemDocItemDoc doc = JSONUtil.toBean(json, ItemDoc.class);//處理高亮字段Map<String, HighlightField> hfs = hit.getHighlightFields();if (hfs != null && !hfs.isEmpty()) {//更具高亮字段名獲取高亮結(jié)果HighlightField hf = hfs.get("name");//用獲取到的高亮值覆蓋原來(lái)非高亮的字段值String hfName = hf.getFragments()[0].toString();doc.setName(hfName);}System.out.println("doc = " + doc);}}//查詢?nèi)?#64;Testvoid testMatchAll() throws IOException {//創(chuàng)建SearchRequest request = new SearchRequest("items");//組織DSL查詢參數(shù)request.source().query(QueryBuilders.matchAllQuery());//發(fā)送請(qǐng)求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析結(jié)果parseResponseResult(response);}//根據(jù)條件查詢:復(fù)合查詢@Testvoid testSearch() throws IOException {//創(chuàng)建SearchRequest request = new SearchRequest("items");//組織DSL查詢參數(shù)request.source().query(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name", "脫脂牛奶")).filter(QueryBuilders.termQuery("brand", "德亞")).filter(QueryBuilders.rangeQuery("price").lt(30000)));//發(fā)送請(qǐng)求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析結(jié)果parseResponseResult(response);}//分頁(yè)排序@Testvoid testPageAndSort() throws IOException {int pageNo = 1, pageSize = 5;// 1.創(chuàng)建RequestSearchRequest request = new SearchRequest("items");// 2.組織請(qǐng)求參數(shù)// 2.1.搜索條件參數(shù)request.source().query(QueryBuilders.matchQuery("name", "脫脂牛奶"));// 2.2.排序參數(shù)request.source().sort("price", SortOrder.ASC);// 2.3.分頁(yè)參數(shù)request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.發(fā)送請(qǐng)求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析響應(yīng)parseResponseResult(response);}//根據(jù)條件獲取高亮數(shù)據(jù)@Testvoid testHighlight() throws IOException {//創(chuàng)建SearchRequest request = new SearchRequest("items");//組織DSL查詢參數(shù)//query條件request.source().query(QueryBuilders.matchQuery("name", "脫脂牛奶"));//高亮條件request.source().highlighter(SearchSourceBuilder.highlight().field("name"));//發(fā)送請(qǐng)求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析結(jié)果parseResponseResult(response);}//數(shù)據(jù)聚合@Testvoid testAgg() throws IOException {//創(chuàng)建SearchRequest request = new SearchRequest("items");//組織DSL查詢參數(shù)//query條件request.source().size(0);//聚合條件String brandAggName = "brandAgg";request.source().aggregation(AggregationBuilders.terms(brandAggName).field("brand").size(10));//發(fā)送請(qǐng)求SearchResponse response = client.search(request, RequestOptions.DEFAULT);//解析結(jié)果Aggregations aggregations = response.getAggregations();//根據(jù)聚合名稱獲取聚合Terms aggTerms = aggregations.get(brandAggName);//獲取bucketsList<? extends Terms.Bucket> buckets = aggTerms.getBuckets();//遍歷每一個(gè)bucketfor (Terms.Bucket bucket : buckets) {System.out.println("brand:"+bucket.getKeyAsString());System.out.println("count:"+bucket.getDocCount());}}@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.181.32:9200")));}@AfterEachvoid tearDown() throws IOException {if (client != null) {client.close();}}
}