文章目錄
-
- ElasticSearch概述
- ES和solr的差别
-
- Lucene簡介
-
- 比較
- ElasticSearch安裝
-
- 1、下載下傳
- 2、熟悉目錄
- 3、啟動,通路9200
- 4、安裝可視化插件
- ES核心概念
- IK分詞器插件
- Rest風格說明
- 關于索引的基本操作
- 關于文檔的基本操作(重點)
- 內建SpringBoot
ElasticSearch概述
Lucene 和 ElasticSearch 關系:
ElasticSearch 是基于 Lucene 做了一些封裝和增強
Elaticsearch,簡稱為es, es是一個開源的高擴充的分布式全文檢索引擎,它可以近乎實時的存儲、檢 索資料;本身擴充性很好,可以擴充到上百台伺服器,處理PB級别(大資料時代)的資料。es也使用 Java開發并使用Lucene作為其核心來實作所有索引和搜尋的功能,但是它的目的是通過簡單的RESTful API來隐藏Lucene的複雜性,進而讓全文搜尋變得簡單。
用途
1、維基百科,類似百度百科,全文檢索,高亮,搜尋推薦/2 (權重,百度!)
2、The Guardian(國外新聞網站),類似搜狐新聞,使用者行為日志(點選,浏覽,收藏,評論)+社交 網絡資料(對某某新聞的相關看法),資料分析,給到每篇新聞文章的作者,讓他知道他的文章的公衆 回報(好,壞,熱門,垃圾,鄙視,崇拜)
3、Stack Overflow(國外的程式異常讨論論壇),IT問題,程式的報錯,送出上去,有人會跟你讨論和 回答,全文檢索,搜尋相關問題和答案,程式報錯了,就會将報錯資訊粘貼到裡面去,搜尋有沒有對應 的答案
4、GitHub(開源代碼管理),搜尋上千億行代碼
5、電商網站,檢索商品
6、日志資料分析,logstash采集日志,ES進行複雜的資料分析,ELK技術, elasticsearch+logstash+kibana
7、商品價格監控網站,使用者設定某商品的價格門檻值,當低于該門檻值的時候,發送通知消息給使用者,比如 說訂閱牙膏的監控,如果高露潔牙膏的家庭套裝低于50塊錢,就通知我,我就去買。
8、BI系統,商業智能,Business Intelligence。比如說有個大型商場集團,BI,分析一下某某區域最近 3年的使用者消費金額的趨勢以及使用者群體的組成構成,産出相關的數張報表,**區,最近3年,每年消費 金額呈現100%的增長,而且使用者群體85%是進階白領,開一個新商場。ES執行資料分析和挖掘, Kibana進行資料可視化
9、國内:站内搜尋(電商,招聘,門戶,等等),IT系統搜尋(OA,CRM,ERP,等等),資料分析 (ES熱門 的一個使用場景)
ES和solr的差别
Lucene簡介
Lucene是apache軟體基金會4 jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具 包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引 引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是為軟體開發人員提供一個簡單 易用的工具包,以友善的在目标系統中實作全文檢索的功能,或者是以此為基礎建立起完整的全文檢索 引擎。Lucene是一套用于全文檢索和搜尋的開源程式庫,由Apache軟體基金會支援和提供。Lucene提 供了一個簡單卻強大的應用程式接口,能夠做全文索引和搜尋。在Java開發環境裡Lucene是一個成熟的 免費開源工具。就其本身而言,Lucene是目前以及最近幾年最受歡迎的免費Java資訊檢索程式庫。人們 經常提到資訊檢索程式庫,雖然與搜尋引擎有關,但不應該将資訊檢索程式庫與搜尋引擎相混淆。
Lucene是一個全文檢索引擎的架構。那什麼是全文搜尋引擎? 全文搜尋引擎是名副其實的搜尋引擎,國外具代表性的有Google、Fast/AllTheWeb、AltaVista、 Inktomi、Teoma、WiseNut等,國内著名的有百度(Baidu)。它們都是通過從網際網路上提取的各個網 站的資訊(以網頁文字為主)而建立的資料庫中,檢索與使用者查詢條件比對的相關記錄,然後按一定的 排列順序将結果傳回給使用者,是以他們是真正的搜尋引擎。
從搜尋結果來源的角度,全文搜尋引擎又可細分為兩種,一種是擁有自己的檢索程式(Indexer),俗稱 “蜘蛛”(Spider)程式或“機器人”(Robot)程式,并自建網頁資料庫,搜尋結果直接從自身的資料庫中 調用,如上面提到的7家引擎;另一種則是租用其他引擎的資料庫,并按自定的格式排列搜尋結果,如 Lycos引擎。
比較
1、es基本是開箱即用(解壓就可以用 ! ),非常簡單。Solr安裝略微複雜一丢丢!
2、Solr 利用 Zookeeper 進行分布式管理,而 Elasticsearch 自身帶有分布式協調管理功能。
3、Solr 支援更多格式的資料,比如JSON、XML、CSV,而 Elasticsearch 僅支援json檔案格式。
4、Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,進階功能多有第三方插件提 供,例如圖形化界面需要kibana友好支撐~!
5、Solr 查詢快,但更新索引時慢(即插入删除慢),用于電商等查詢多的應用;
- ES建立索引快(即查詢慢),即實時性查詢快,用于facebook新浪等搜尋。
- Solr 是傳統搜尋應用的有力解決方案,但 Elasticsearch 更适用于新興的實時搜尋應用。
6、Solr比較成熟,有一個更大,更成熟的使用者、開發和貢獻者社群,而 Elasticsearch相對開發維護者較少,更新太快,學習使用成本較高。(趨勢!)
ElasticSearch安裝
聲明:JDK1.8 ,最低要求! ElasticSearch 用戶端,界面工具!
1、下載下傳
官網
下載下傳位址
2、熟悉目錄
bin 啟動檔案
config 配置檔案
log4j2 日志配置檔案
jvm.options java 虛拟機相關的配置
elasticsearch.yml elasticsearch 的配置檔案! 預設 9200 端口! 跨域!
lib 相關jar包
logs 日志!
modules 功能子產品
plugins 插件!
3、啟動,通路9200
4、安裝可視化插件
安裝可視化界面 es head的插件
1、下載下傳位址
2、啟動
npm install
npm run start
3、連接配接測試發現,存在跨域問題:配置es
http.cors.enabled: true
http.cors.allow-origin: "*"
4、重新開機es伺服器,然後再次連接配接
就把es當做一個資料庫! (可以建立索引(庫),文檔(庫中的資料!)) 這個head我們就把它當做資料展示工具!我們後面所有的查詢,Kibana!
了解 ELK
ELK是Elasticsearch、Logstash、Kibana三大開源架構首字母大寫簡稱。市面上也被成為Elastic Stack。其中Elasticsearch是一個基于Lucene、分布式、通過Restful方式進行互動的近實時搜尋平台框 架。像類似百度、谷歌這種大資料全文搜尋引擎的場景都可以使用Elasticsearch作為底層支援架構,可見Elasticsearch提供的搜尋能力确實強大,市面上很多時候我們簡稱Elasticsearch為es。
Logstash是ELK 的中央資料流引擎,用于從不同目标(檔案/資料存儲/MQ)收集的不同格式資料,經過過濾後支援輸出 到不同目的地(檔案/MQ/redis/elasticsearch/kafka等)。Kibana可以将elasticsearch的資料通過友好 的頁面展示出來,提供實時分析的功能。
市面上很多開發隻要提到ELK能夠一緻說出它是一個日志分析架構技術棧總稱,但實際上ELK不僅僅适用 于日志分析,它還可以支援其它任何資料分析和收集的場景,日志分析和收集隻是更具有代表性。并非 唯一性。

官網
Kibana 版本要和 Es 一緻!
啟動測試:
1、解壓後端的目錄
2、啟動
3、通路測試
4、開發工具! (Post、curl、head、谷歌浏覽器插件測試!)
5、漢化!自己修改kibana配置即可! zh-CN!
ES核心概念
1、索引
2、字段類型(mapping)
3、文檔(documents)
elasticsearch是面向文檔,關系行資料庫 和 elasticsearch 客觀的對比!一切都是JSON
Relational DB | Elasticsearch |
---|---|
資料庫(database) | 索引(indices) |
表(tables) | types |
行(rows) | documents |
字段(columns) | fields |
elasticsearch(叢集)中可以包含多個索引(資料庫),每個索引中可以包含多個類型(表),每個類型下又包 含多 個文檔(行),每個文檔中又包含多個字段(列)。
實體設計:
elasticsearch 在背景把每個索引劃分成多個分片,每分分片可以在叢集中的不同伺服器間遷移 一個人就是一個叢集!預設的叢集名稱就是 elaticsearh
邏輯設計:
一個索引類型中,包含多個文檔,比如說文檔1,文檔2。 當我們索引一篇文檔時,可以通過這樣的一各 順序找到 它: 索引 ▷ 類型 ▷ 文檔ID ,通過這個組合我們就能索引到某個具體的文檔。 注意:ID不必是整 數,實際上它是個字 符串。
文檔
就是我們的一條資料
之前說elasticsearch是面向文檔的,那麼就意味着索引和搜尋資料的最小機關是文檔,elasticsearch 中,文檔有幾個 重要屬性 :
- 自我包含,一篇文檔同時包含字段和對應的值,也就是同時包含 key:value!
- 可以是層次型的,一個文檔中包含自文檔,複雜的邏輯實體就是這麼來的! {就是一個json對象! fastjson進行自動轉換!}
- 靈活的結構,文檔不依賴預先定義的模式,我們知道關系型資料庫中,要提前定義字段才能使用, 在elasticsearch中,對于字段是非常靈活的,有時候,我們可以忽略該字段,或者動态的添加一個 新的字段。
盡管我們可以随意的新增或者忽略某個字段,但是,每個字段的類型非常重要,比如一個年齡字段類 型,可以是字元 串也可以是整形。因為elasticsearch會儲存字段和類型之間的映射及其他的設定。這種 映射具體到每個映射的每種類型,這也是為什麼在elasticsearch中,類型有時候也稱為映射類型 。
類型
類型是文檔的邏輯容器,就像關系型資料庫一樣,表格是行的容器。 類型中對于字段的定義稱為映射, 比如 name 映 射為字元串類型。 我們說文檔是無模式的,它們不需要擁有映射中所定義的所有字段, 比如新增一個字段,那麼elasticsearch是怎麼做的呢?elasticsearch會自動的将新字段加入映射,但是這 個字段的不确定它是什麼類型,elasticsearch就開始猜,如果這個值是18,那麼elasticsearch會認為它 是整形。 但是elasticsearch也可能猜不對, 是以最安全的方式就是提前定義好所需要的映射,這點跟關 系型資料庫殊途同歸了,先定義好字段,然後再使用,别 整什麼幺蛾子
索引
就是資料庫!
索引是映射類型的容器,elasticsearch中的索引是一個非常大的文檔集合。索引存儲了映射類型的字段 和其他設定。 然後它們被存儲到了各個分片上了。 我們來研究下分片是如何工作的。
一個叢集至少有一個節點,而一個節點就是一個elasricsearch程序,節點可以有多個索引預設的,如果你建立索引,那麼索引将會有個5個分片 ( primary shard ,又稱主分片 ) 構成的,每一個主分片會有一個 副本 ( replica shard ,又稱複制分片 )
倒排
索引 elasticsearch使用的是一種稱為反向索引的結構,采用Lucene倒排索作為底層。這種結構适用于快速的全文搜尋, 一個索引由文檔中所有不重複的清單構成,對于每一個詞,都有一個包含它的文檔清單。 例 如,現在有兩個文檔, 每個文檔包含如下内容:
Study every day, good good up to forever # 文檔1包含的内容
To forever, study every day, good good up # 文檔2包含的内容
為了建立反向索引,我們首先要将每個文檔拆分成獨立的詞(或稱為詞條或者tokens),然後建立一個包含所有不重 複的詞條的排序清單,然後列出每個詞條出現在哪個文檔
term | doc_1 | doc_2 |
---|---|---|
Study | √ | × |
To | x | x |
every | √ | √ |
foreve | √ | √ |
day | × | √ |
study | √ | √ |
good | √ | √ |
every | √ | √ |
to | √ | × |
up | √ | √ |
現在,我們試圖搜尋 to forever,隻需要檢視包含每個詞條的文檔 score
term | doc_1 | doc_2 |
---|---|---|
to | √ | × |
forever | √ | √ |
total | 2 | 1 |
如果沒有别的條件,現在,這兩個包含關鍵字的文檔都将傳回。
在elasticsearch中, 索引 (庫)這個詞被頻繁使用,這就是術語的使用。 在elasticsearch中,索引被 分為多個分片,每份 分片是一個Lucene的索引。是以一個elasticsearch索引是由多個Lucene索引組成 的。别問為什麼,誰讓elasticsearch使用Lucene作為底層呢! 如無特指,說起索引都是指elasticsearch 的索引。
IK分詞器插件
什麼是IK分詞器?
分詞:即把一段中文或者别的劃分成一個個的關鍵字,我們在搜尋時候會把自己的資訊進行分詞,會把資料庫中或者索引庫中的資料進行分詞,然後進行一個比對操作,預設的中文分詞是将每個字看成一個 詞,比如 “我愛狂神” 會被分為"我",“愛”,“狂”,“神”,這顯然是不符合要求的,是以我們需要安裝中文分詞 器ik來解決這個問題。
如果要使用中文,建議使用ik分詞器!
IK提供了兩個分詞算法:ik_smart 和 ik_max_word,其中 ik_smart 為最少切分,ik_max_word為最細 粒度劃分!
安裝
1、https://github.com/medcl/elasticsearch-analysis-ik
2、下載下傳完畢之後,放入到我們的elasticsearch 插件即可!
3、重新開機觀察ES,可以看到ik分詞器被加載了!
4、elasticsearch-plugin 可以通過這個指令來檢視加載進來的插件
5、使用kibana測試!
安裝插件錯誤
Plugin [analysis-pinyin] was built for Elasticsearch version 7.6.1 but versin 7.6.2 is running
解決辦法
進入 plugin的descriptor.properties
修改 elasticsearch.version為你自己的版本
檢視不同的分詞效果
GET _analyze
{
"analyzer": "ik_smart",
"text": "中國共産黨"
}
GET _analyze
{
"analyzer": "ik_max_word",
"text": "中國共産黨"
}
其中 ik_smart 為最少切分
ik_max_word為最細粒度劃分!窮盡詞庫的可能!字典!
ik 分詞器增加自己的配置!
有可能詞庫不認得單詞才分成一個一個的字
沒有成功
Rest風格說明
一種軟體架構風格,而不是标準,隻是提供了一組設計原則和限制條件。它主要用于用戶端和伺服器交 互類的軟體。基于這個風格設計的軟體可以更簡潔,更有層次,更易于實作緩存等機制。
基本Rest指令說明:
method | url位址 | 描述 |
---|---|---|
PUT | localhost:9200/索引名稱/類型名稱/文檔id | 建立文檔(指定文檔id) |
POST | localhost:9200/索引名稱/類型名稱 | 建立文檔(随機文檔id) |
_update | localhost:9200/索引名稱/類型名稱/文檔id/_update | 修改文檔 |
DELETE | localhost:9200/索引名稱/類型名稱/文檔id | 删除文檔 |
GET | localhost:9200/索引名稱/類型名稱/文檔id | 查詢文檔通過文檔id |
POST | localhost:9200/索引名稱/類型名稱/_search | 查詢所有資料 |
關于索引的基本操作
1、建立一個索引
PUT /索引名/~類型名~/文檔id
{請求體}
3、需要指定類型的啊 !
字元串類型
text 、 keyword
數值類型
long, integer, short, byte, double, float, half_float, scaled_float
日期類型
te布爾值類型
boolean
二進制類型
binary 等等…
增删改查
PUT /test1/type1/1
{
"name":"狂神說",
"age": 3
}
PUT /test2
{
"mappings":{
"properties" :{
"name":{
"type" : "text"
},
"age":{
"type":"long"
},
"birthday":{
"type":"date"
}
}
}
}
GET test2
PUT /test3/_doc/1
{
"name":"陳玲琦",
"age": 13,
"birth" : "1994-05-14"
}
GET test3
GET _cat/health
GET _cat/indices?v
GET test3
POST /test3/_doc/1/_update
{
"doc":{
"name":"法外狂徒張三"
}
}
DELETE test1
DELETE test1/type1/1
關于文檔的基本操作(重點)
基本操作
1、添加資料
PUT /kuangshen/user/1
{
"name": "狂神說",
"age": 23,
"desc": "一頓操作猛如虎,一看工資2500",
"tags": ["技術宅","溫暖","直男"]
}
2、擷取資料 GET
GET /kuangshen/user/1
3、更新資料 PUT
- 必須對應的值分别都需要傳值,不然會被覆寫
4、 Post _update , 推薦使用這種更新方式!
POST kuangshen/user/3/_update
{
"doc":{
"name":"狂神說java"
}
}
簡單地搜尋!
GET kuangshen/user/1
_search
GET kuangshen/user/_search?q=name:狂神說java
GET kuangshen/user/_search
{
"query":{
"match":{
"name":"狂神說"
}
}
}
結果:
"hits" : [
{
"_index" : "kuangshen",
"_type" : "user",
"_id" : "1",
"_score" : 1.6594179,
"_source" : {
"name" : "狂神說",
"age" : 23,
"desc" : "一頓操作猛如虎,一看工資2500",
"tags" : [
"技術宅",
"溫暖",
"直男"
]
}
},
_source 進行對字段進行過濾
GET kuangshen/user/_search
{
"query":{
"match":{
"name":"狂神說"
}
},
"_source":["name","age"]
}
sort 排序!
"sort": [
{
"FIELD": {
"order": "desc"或者asc
}
}
]
分頁查詢
"from": 起始值
"size": 大小
GET kuangshen/user/_search
{
"query":{
"match":{
"name":"狂神說"
}
},
"sort": [
{
"age": {
"order": "desc"
}
}
],
"from":0,
"size": 1
}
must (and),所有的條件都要符合 where id = 1 and name = xxx
GET kuangshen/user/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "狂神說"
}
},
{
"match": {
"age": "30"
}
}
]
}
}
}
should(or),所有的條件都要符合 where id = 1 or name = xxx
must_not (not)
過濾器 filter
- gt 大于
- gte 大于等于
- lt小于
- lte 小于等于!
"filter": [
{"range": {
"age": {
"gte": 10,
"lte": 30
}
}}
]
比對多個條件!
"query": {
"match": {
"tags": "男 暖"
}
}
term
查詢是直接通過反向索引指定的詞條程序精确查找的!
關于分詞:
- term ,直接查詢精确的
- match,會使用分詞器解析!(先分析文檔,然後在通過分析的文檔進行查詢!)
兩個類型 text keyword
高亮查詢!
GET kuangshen/user/_search
{
"query": {
"match": {
"name":"java"
}
},
"highlight": {
"fields": {
"name":{}
}
}
}
自定義搜尋高亮
"highlight": {
"pre_tags": "<p class='key' style='color:red' >",
"post_tags": "</p>",
"fields": {
"name":{}
}
- 比對
- 按照條件比對
- 精确比對
- 區間範圍比對
- 比對字段過濾
- 多條件查詢
- 高亮查詢
內建SpringBoot
學習文檔
API位址
1、找到原生的依賴
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.2</version>
</dependency
2、找對象
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")));
client.close();
3、分析這個類中的方法即可!
問題:一定要保證 我們的導入的依賴和我們的es 版本一緻
用戶端自動配置的類
ElasticsearchAutoConfiguration.class,
RestClientAutoConfiguration.class,
ReactiveRestClientAutoConfiguration.class
配置的類
class RestClientConfigurations {
@Configuration(proxyBeanMethods = false)
static class RestClientBuilderConfiguration {
// RestClientBuilder
@Bean
@ConditionalOnMissingBean
RestClientBuilder elasticsearchRestClientBuilder(RestClientProperties
properties,
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
HttpHost[] hosts =
properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);
RestClientBuilder builder = RestClient.builder(hosts);
PropertyMapper map = PropertyMapper.get();
map.from(properties::getUsername).whenHasText().to((username) -> {
CredentialsProvider credentialsProvider = new
BasicCredentialsProvider();
Credentials credentials = new
UsernamePasswordCredentials(properties.getUsername(),
properties.getPassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
builder.setHttpClientConfigCallback(
(httpClientBuilder) ->
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
});
builder.setRequestConfigCallback((requestConfigBuilder) -> {
map.from(properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMill
is)
.to(requestConfigBuilder::setConnectTimeout);
map.from(properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
.to(requestConfigBuilder::setSocketTimeout);
return requestConfigBuilder;
});
builderCustomizers.orderedStream().forEach((customizer) ->
customizer.customize(builder));
return builder;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)
static class RestHighLevelClientConfiguration {
// RestHighLevelClient 進階用戶端,也是我們這裡要講,後面項目會用到的用戶端
@Bean
@ConditionalOnMissingBean
RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder
restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder,
ObjectProvider<RestHighLevelClient> restHighLevelClient) {
RestHighLevelClient client = restHighLevelClient.getIfUnique();
if (client != null) {
return client.getLowLevelClient();
}
return builder.build();
}
}
@Configuration(proxyBeanMethods = false)
static class RestClientFallbackConfiguration {
// RestClient 普通的用戶端!
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder) {
return builder.build();
}
}
}
3
具體的Api測試!
- 1、建立索引
- 2、判斷索引是否存在
- 3、删除索引
- 4、建立文檔
- 5、crud文檔!
package com.kuang;
import com.alibaba.fastjson.JSON;
import com.kuang.pojo.User;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class ElasticApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
//測試建立索引
@Test
void testCreateIndex() throws IOException {
//1、建立索引請求
CreateIndexRequest request = new CreateIndexRequest("kuang_index");
//2、用戶端執行請求 IndicesClient,請求後獲得響應
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(response);
}
//測試獲得索引,判斷是不是存在
@Test
void testExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("kuang_index");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
//測試删除索引
@Test
void testRemoveIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("kuang_index");
AcknowledgedResponse exists = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(exists.isAcknowledged());
}
//測試添加文檔
@Test
void testAddDocument() throws IOException {
User user = new User("狂神說", 3);
//擷取請求索引
IndexRequest request = new IndexRequest("kuang_index");
//設定請求規則
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.timeout("1s");
//将資料放到請求中
request.source(JSON.toJSONString(user), XContentType.JSON);
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());
System.out.println(indexResponse.status());
}
// 擷取文檔,判斷是否存在 get /index/doc/1
@Test
void testIsExists() throws IOException {
GetRequest getRequest = new GetRequest("kuang_index", "1");
// 不擷取傳回的 _source 的上下文了
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
// 獲得文檔的資訊
@Test
void testGetDocument() throws IOException {
GetRequest getRequest = new GetRequest("kuang_index", "1");
GetResponse getResponse = client.get(getRequest,
RequestOptions.DEFAULT);
System.out.println(getResponse.getSourceAsString()); // 列印文檔的内容
System.out.println(getResponse); // 傳回的全部内容和指令式一樣的
}
// 更新文檔的資訊
@Test
void testUpdateRequest() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("kuang_index", "1");
updateRequest.timeout("1s");
User user = new User("狂神說Java", 18);
updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
UpdateResponse updateResponse = client.update(updateRequest,
RequestOptions.DEFAULT);
System.out.println(updateResponse.status());
}
// 删除文檔記錄
@Test
void testDeleteRequest() throws IOException {
DeleteRequest request = new DeleteRequest("kuang_index", "1");
request.timeout("1s");
DeleteResponse deleteResponse = client.delete(request,
RequestOptions.DEFAULT);
System.out.println(deleteResponse.status());
}
// 特殊的,真的項目一般都會批量插入資料!
@Test
void testBulkRequest() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("kuangshen1",3));
userList.add(new User("kuangshen2",3));
userList.add(new User("kuangshen3",3));
userList.add(new User("qinjiang1",3));
userList.add(new User("qinjiang1",3));
userList.add(new User("qinjiang1",3));
// 批處理請求
for (int i = 0; i < userList.size() ; i++) {
// 批量更新和批量删除,就在這裡修改對應的請求就可以了
bulkRequest.add(
new IndexRequest("kuang_index")
.id(""+(i+1))
.source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
}
BulkResponse bulkResponse = client.bulk(bulkRequest,
RequestOptions.DEFAULT);
client.close();
System.out.println(bulkResponse.hasFailures()); // 是否失敗,傳回 false 代表成功!
}
// 查詢
// SearchRequest 搜尋請求
// SearchSourceBuilder 條件構造
// HighlightBuilder 建構高亮
// TermQueryBuilder 精确查詢
// MatchAllQueryBuilder
// xxx QueryBuilder 對應我們剛才看到的指令!
@Test
void testSearch() throws IOException {
SearchRequest searchRequest = new SearchRequest("kuang_index");
// 建構搜尋條件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.highlighter();
// 查詢條件,我們可以使用 QueryBuilders 工具來實作
// QueryBuilders.termQuery 精确
// QueryBuilders.matchAllQuery() 比對所有
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name",
"qinjiang1");
// MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest,RequestOptions.DEFAULT);
System.out.println(JSON.toJSONString(searchResponse.getHits()));
System.out.println("=================================");
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
System.out.println(documentFields.getSourceAsMap());
}
}
}