1. 程式人生 > 實用技巧 >ElasticSearch學習

ElasticSearch學習

轉載:https://blog.csdn.net/JENREY/article/details/81290535?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param#4.2%20%E5%AE%89%E8%A3%85%E5%B9%B6%E5%90%AF%E5%8A%A8EShttps://home.firefoxchina.cn

目錄

1.ElasticSearch的簡介

2.用資料庫實現搜素的功能

3.ES的核心概念

3.1 NRT(Near Realtime)近實時

3.2 cluster叢集,ES是一個分散式的系統

3.3 Node節點,就是叢集中的一臺伺服器

3.4 index 索引(索引庫)

3.5 type型別

3.6 document:文件

3.7 Field 欄位

3.8 shard:分片

3.9 relica:副本

總結:

4. ES叢集的安裝

4.1 下載

4.2 安裝並啟動ES

5. 安裝 Kibana

5.1 為什麼要安裝

5.2 安裝並啟動

5.3 引數解析:

6. ES的相關命令

7. ES的CURD操作

8.DSL語言

9.聚合分析

10.ES的隱藏性

11.ES叢集的擴容問題

12.對等式架構

13.ES的primary shard和replica shard

14.ES的容錯機制

15.自動生成ID號

16.version之悲觀鎖和樂觀鎖

17.ES實戰之專案效果

18.專案實戰

1)首先用IDEA新建web maven專案


1.ElasticSearch的簡介

ElasticSearch:智慧搜尋,分散式的搜尋引擎

是ELK的一個組成,是一個產品,而且是非常完善的產品,ELK代表的是:E就是ElasticSearch,L就是Logstach,K就是kibana

E:EalsticSearch 搜尋和分析的功能

L:Logstach 蒐集資料的功能,類似於flume(使用方法幾乎跟flume一模一樣),是日誌收集系統

K:Kibana 資料視覺化(分析),可以用圖表的方式來去展示,文不如表,表不如圖,是資料視覺化平臺

分析日誌的用處:假如一個分散式系統有 1000 臺機器,系統出現故障時,我要看下日誌,還得一臺一臺登入上去檢視,是不是非常麻煩?

但是如果日誌接入了 ELK 系統就不一樣。比如系統執行過程中,突然出現了異常,在日誌中就能及時反饋,日誌進入 ELK 系統中,我們直接在 Kibana 就能看到日誌情況。如果再接入一些實時計算模組,還能做實時報警功能。

這都依賴ES強大的反向索引功能,這樣我們根據關鍵字就能查詢到關鍵的錯誤日誌了。

什麼是搜尋?

1)百度,谷歌,必應。我們可以通過他們去搜索我們需要的東西。但是我們的搜尋不只是包含這些,還有京東站內搜尋啊。

2)網際網路的搜尋:電商網站。招聘網站。新聞網站。各種APP(百度外賣,美團等等)

3)windows系統的搜尋,OA軟體,淘寶SSM網站,前後臺的搜尋功能

總結:搜尋無處不在。通過一些關鍵字,給我們查詢出來跟這些關鍵字相關的資訊

什麼是全文檢索

全文檢索是指計算機索引程式通過掃描文章中的每一個詞,對每一個詞建立一個索引,指明該詞在文章中出現的次數和位置,當用戶查詢時,檢索程式就根據事先建立的索引進行查詢,並將查詢的結果反饋給使用者的檢索方式。這個過程類似於通過字典中的檢索字表查字的過程。

全文檢索的方法主要分為按字檢索和按詞檢索兩種。按字檢索是指對於文章中的每一個字都建立索引,檢索時將詞分解為字的組合。對於各種不同的語言而言,字有不同的含義,比如英文中字與詞實際上是合一的,而中文中字與詞有很大分別。按詞檢索指對文章中的詞,即語義單位建立索引,檢索時按詞檢索,並且可以處理同義項等。英文等西方文字由於按照空白切分詞,因此實現上與按字處理類似,新增同義處理也很容易。中文等東方文字則需要切分字詞,以達到按詞索引的目的,關於這方面的問題,是當前全文檢索技術尤其是中文全文檢索技術中的難點,在此不做詳述。

什麼是倒排索引

以前是根據ID查內容,倒排索引之後是根據內容查ID,然後再拿著ID去查詢出來真正需要的東西。

什麼是Lucene

Lucene就是一個jar包,裡面包含了各種建立倒排索引的方法,java開發的時候只需要匯入這個jar包就可以開發了。

Lucene的介紹及使用

典型的用空間換時間。

ES 和 Lucene的區別

Lucene不是分散式的。

ES的底層就是Lucene,ES是分散式的

為什麼不用資料庫去實現搜尋功能?

我們用搜索“牙膏”商品為例

如果用我們平時資料庫來實現搜尋的功能在效能上就很差。

ES的官網

ES官網點我

簡單使用如下圖,可以切換成中文的文件

或者使用spark的中文網站,也有ES的文件,傳送門在下面

ES中文文件

ES的由來

因為Lucene有兩個難以解決的問題,

1)資料越大,存不下來,那我就需要多臺伺服器存資料,那麼我的Lucene不支援分散式的,那就需要安裝多個Lucene然後通過程式碼來合併搜尋結果。這樣很不好

2)資料要考慮安全性,一臺伺服器掛了,那麼上面的資料不就消失了。

ES就是分散式的叢集,每一個節點其實就是Lucene,當用戶搜尋的時候,會隨機挑一臺,然後這臺機器自己知道資料在哪,不用我們管這些底層、

ES的優點

1.分散式的功能

2、資料高可用,叢集高可用

3.API更簡單

4.API更高階。

5.支援的語言很多

6.支援PB級別的資料

7.完成搜尋的功能和分析功能

基於Lucene,隱藏了Lucene的複雜性,提供簡單的API

ES的效能比HBase高,咱們的競價引擎最後還是要存到ES中的。

搜尋引擎原理

  • 反向索引又叫倒排索引,是根據文章內容中的關鍵字建立索引。
  • 搜尋引擎原理就是建立反向索引。
  • Elasticsearch 在 Lucene 的基礎上進行封裝,實現了分散式搜尋引擎。
  • Elasticsearch 中的索引、型別和文件的概念比較重要,類似於 MySQL 中的資料庫、表和行。
  • Elasticsearch 也是 Master-slave 架構,也實現了資料的分片和備份。
  • Elasticsearch 一個典型應用就是 ELK 日誌分析系統。

ES支援的語言

Curl、java、c#、python、JavaScript、php、perl、ruby

Curl 'www.baidu.com' 就是linux的shell命令。可以訪問百度,返回的是百度的網頁程式碼

ES的作用

1)全文檢索:

類似 select * from product whereproduct_name like '%牙膏%'

類似百度效果(電商搜尋的效果)

2)結構化搜尋:

類似 select * from product where product_id = '1'

3)資料分析

類似 select count (*) from product

ES的安裝

直接解壓就能用(針對中小型專案),大型專案還是要調一調引數的

2.用資料庫實現搜素的功能

3.ES的核心概念

3.1 NRT(Near Realtime)近實時

3.2 cluster叢集,ES是一個分散式的系統

ES直接解壓不需要配置就可以使用,在hadoop1上解壓一個ES,在hadoop2上解壓了一個ES,接下來把這兩個ES啟動起來。他們就構成了一個叢集。

在ES裡面預設有一個配置,clustername預設值就是ElasticSearch,如果這個值是一樣的就屬於同一個叢集,不一樣的值就是不一樣的叢集。

3.3 Node節點,就是叢集中的一臺伺服器

3.4 index 索引(索引庫)

我們為什麼使用ES?因為想把資料存進去,然後再查詢出來。

我們在使用Mysql或者Oracle的時候,為了區分資料,我們會建立不同的資料庫,庫下面還有表的。

其實ES功能就像一個關係型資料庫,在這個資料庫我們可以往裡面新增資料,查詢資料。

ES中的索引非傳統索引的含義,ES中的索引是存放資料的地方,是ES中的一個概念詞彙

index類似於我們Mysql裡面的一個數據庫 create database user; 好比就是一個索引庫

3.5 type型別

型別是用來定義資料結構的

在每一個index下面,可以有一個或者多個type,好比資料庫裡面的一張表。

相當於表結構的描述,描述每個欄位的型別。

3.6 document:文件

文件就是最終的資料了,可以認為一個文件就是一條記錄。

是ES裡面最小的資料單元,就好比表裡面的一條資料

3.7 Field 欄位

好比關係型資料庫中列的概念,一個document有一個或者多個field組成。

例如:

朝陽區:一個Mysql資料庫

房子:create database chaoyaninfo

房間:create table people

3.8 shard:分片

一臺伺服器,無法儲存大量的資料,ES把一個index裡面的資料,分為多個shard,分散式的儲存在各個伺服器上面。

kafka:為什麼支援分散式的功能,因為裡面是有topic,支援分割槽的概念。所以topic A可以存在不同的節點上面。就可以支援海量資料和高併發,提升效能和吞吐量

3.9 replica:副本

一個分散式的叢集,難免會有一臺或者多臺伺服器宕機,如果我們沒有副本這個概念。就會造成我們的shard發生故障,無法提供正常服務。

我們為了保證資料的安全,我們引入了replica的概念,跟hdfs裡面的概念是一個意思。

可以保證我們資料的安全。

在ES叢集中,我們一模一樣的資料有多份,能正常提供查詢和插入的分片我們叫做 primary shard,其餘的我們就管他們叫做 replica shard(備份的分片)

當我們去查詢資料的時候,我們資料是有備份的,它會同時發出命令讓我們有資料的機器去查詢結果,最後誰的查詢結果快,我們就要誰的資料(這個不需要我們去控制,它內部就自己控制了)

總結:

在預設情況下,我們建立一個庫的時候,預設會幫我們建立5個主分片(primary shrad)和5個副分片(replica shard),所以說正常情況下是有10個分片的。

同一個節點上面,副本和主分片是一定不會在一臺機器上面的,就是擁有相同資料的分片,是不會在同一個節點上面的。

所以當你有一個節點的時候,這個分片是不會把副本存在這僅有的一個節點上的,當你新加入了一臺節點,ES會自動的給你在新機器上建立一個之前分片的副本。

3.10 舉例

比如一首詩,有詩題、作者、朝代、字數、詩內容等欄位,那麼首先,我們可以建立一個名叫 Poems 的索引,然後建立一個名叫 Poem 的型別,型別是通過 Mapping 來定義每個欄位的型別。

比如詩題、作者、朝代都是 Keyword 型別,詩內容是 Text 型別,而字數是 Integer 型別,最後就是把資料組織成 Json 格式存放進去了。

Keyword 型別是不會分詞的,直接根據字串內容建立反向索引,Text 型別在存入 Elasticsearch 的時候,會先分詞,然後根據分詞後的內容建立反向索引。

4. ES叢集的安裝

4.1 下載

點選上面的官網傳送門,點選downloads

下載ES點我

關於ES的版本,現在大多數網上和書寫的都是ES 2.x系列的書,有部分比較新的講的是ES 5的

沒有3,4一說。是這樣的,ELK 產品是一個非常完善的系統,跟大資料沒什麼關係,後來我們發現可以處理一些大資料的東西。可以和hadoop和spark整合。因為ELK三個產品是不同的公司出的。有一天一個人想把它們整合在一起,發現E發展到了2的版本,L發展到了3的版本,K發展到了4的版本。這樣會有一個問題,什麼樣的hive和hbase配合什麼樣的hadoop,這樣引發了一個匹配不匹配的問題。三個廠家就決定,從下一代產品我們一起升級就從5版本開始,所以如果你E用5.6,L也應該用5.6,K也應該用5.6,這樣就進行了匹配。

這裡我們下載安裝目前最新版本的6.3.2的ES,注意需要安裝好JDK,因為是由java開發的。

4.2 安裝並啟動ES

直接解壓即可,進入bin目錄,本文為 G:\myProgram\ElasticSearch\elasticsearch-6.3.2\bin 下進入cmd,

輸入elasticsearch

驗證ES是否啟動成功

在瀏覽器中輸入http://localhost:9200看到如下所示圖片即為成功

4.3 ES的分散式原理

Elasticsearch 也是會對資料進行切分,同時每一個分片會儲存多個副本,其原因和 HDFS 是一樣的,都是為了保證分散式環境下的高可用。

在 Elasticsearch 中,是master-slave架構。節點是對等的,節點間會通過自己的一些規則選取叢集的 Master,Master 會負責叢集狀態資訊的改變,並同步給其他節點。

這樣寫入效能會不會很低???注意,只有建立索引和型別需要經過 Master,資料的寫入有一個簡單的 Routing 規則,可以 Route 到叢集中的任意節點,所以資料寫入壓力是分散在整個叢集的。

5. 安裝 Kibana

5.1 為什麼要安裝

為了方便我們去操作ES,如果不安裝去操作ES很麻煩,需要通過shell命令的方式。

下載Kibana

5.2 安裝並啟動

直接解壓即可,進入bin目錄下,本文為G:\myProgram\kibana\kibana-6.3.2-windows-x86_64\bin 的cmd,執行kibana

不需要配置任何引數,自動識別localhost

在瀏覽器中輸入 http://localhost:5601

然後在左側找到Dev Tools,在這裡就可以進行操作了

輸入GET _cat/health 檢視叢集的健康狀況

5.3 引數解析:

green:每個索引的primary shard和replica shard 都處於active的狀態。

下圖是一個ES叢集有兩個節點。主分片是支撐使用者的讀寫。副只支援讀資料。這樣就造成主分片壓力會大一點,所以ES叢集在分配分片的時候會考慮負載均衡,依據就是按照主分片的情況來。

yellow:每個索引的primary shard是active的狀態,但是部分replica shard不是active的狀態,處於不可用的狀態。

使用GET _cat/indices 命令查詢ES中所有的index

但是可能查詢的不全,我們使用下面的命令

GET _all

但是可能會質疑,我們剛搭建好什麼資料也沒插入,為什麼會有資料查出來。

下面這段話講的是5.6.3版本。

我們通過啟動Kibana進行對接的ES,預設自動在ES上建立了一個index庫,這個庫有個特點,這個庫有一個主分片primary shard,有一個replica shard 副分片

如下圖所示,我們目前windows的狀況是啟動了一個ES的叢集,這個叢集裡面只有一個ES的節點。

然後我們啟動了一個kibana

kibana識別到了這個ES節點,kibana預設在上面建立了一個index,這個index的分片情況是 1 primary shard 和1 replica shard

但是可能咱們現在用的這個版本有了一些優化可能就跟上面說的不一樣了。我們現在ES的狀態是green

如何把叢集的狀態由yellow變成green?

我再啟動一個節點(換個路徑再次解壓ES的壓縮包在啟動起來),讓之前的那個有地方放置就好了。

再次執行查詢健康的命令,效果圖如下

red:不是所有的primary shard 都是active的狀態,這時候是危險的,至少我們不能保證寫資料是安全的。

6. ES的相關命令

這裡的效果圖是沒有搭建第二個ES的節點的(因為電腦空間不太夠了)

GET _cat/health 檢視叢集的健康狀況

GET _all


PUT 類似於SQL中的增

DELETE 類似於SQL中的刪

POST 類似於SQL中的改

GET 類似於SQL中的查


index的操作:

PUT /aura_index 增加一個aura_index的index庫

GET _cat/indices 命令查詢ES中所有的index索引庫

5:代表的是 primary shard的個數

1:代表的是replica shard的個數是5,因為副本數為1代表有5個副分片,注意這個地方說的1是不包括自己本身的,我們的HDFS block3代表的是包括自己本身的

DELETE /aura_index 刪除一個aura_index的index庫

7. ES的CURD操作

通過演示一個電商的例子,感受到ES的語法特點

1)插入一條商品資料

注意:我們插入資料的時候,如果我們的語句中指明瞭index和type,如果ES裡面不存在,預設幫我們自動建立

2)查詢商品資料

使用這種語法: GET /index/type/id

3)修改商品資料

使用POST來修改資料,其實使用PUT也可以實現修改資料,原理和hbase比較像。POST的修改資料的方法在第4條中

換個方式,下面這種操作也是成功的,會丟資料,是全域性的修改

4)刪除商品資料

再次插入之前的資料,發現version是5,這就說明跟hbase是類似的,不會立刻刪除,會在合適的時機進行刪除。

這次我們使用POST的方式進行修改資料,POST是區域性更新資料,別的資料不動。PUT是全域性更新

5)接著插入兩條資料

現在檢視所有資料,類似於全表掃描

took:耗費了6毫秒

shards:分片的情況

hits:獲取到的資料的情況

total:3 總的資料條數

max_score:1 所有資料裡面打分最高的分數

_index:"ecommerce" index名稱

_type:"product" type的名稱

_id:"2" id號

_score:1 分數,這個分數越大越靠前出來,百度也是這樣。除非是花錢。否則匹配度越高越靠前

8.DSL語言

ES最主要是用來做搜尋和分析的。所以DSL還是對於ES很重要的

下面我們寫的程式碼都是RESTful風格

query DSL:domain Specialed Lanaguage 在特定領域的語言

案例:我們要進行全表掃描使用DSL語言,查詢所有的商品

使用match_all可以查詢到所有文件,是沒有查詢條件下的預設語句。

案例:查詢所有名稱裡面包含chenyi的商品,同時按價格進行降序排序

如上圖所示,name為dior chenyi的資料會在ES中進行倒排索引分詞的操作,這樣的資料也會被查詢出來。

match查詢是一個標準查詢,不管你需要全文字查詢還是精確查詢基本上都要用到它。

下面我們按照價格進行排序:因為不屬於查詢的範圍了。所以要寫一個 逗號

這樣我們的排序就完成了

案例:實現分頁查詢

條件:根據查詢結果(包含chenyi的商品),再進行每頁展示2個商品

案例:進行全表掃面,但返回指定欄位的資料

現在的情況是把所有的資料都返回了,但是我們想返回指定欄位的資料內容就需要下面的方法了

案例:搜尋名稱裡面包含chenyi的,並且價格大於250元的商品

相當於 select * form product where name like %chenyi% and price >250;

因為有兩個查詢條件,我們就需要使用下面的查詢方式

如果需要多個查詢條件拼接在一起就需要使用bool

bool過濾可以用來合併多個過濾條件查詢結果的布林邏輯,它包含以下操作符:

must:: 多個查詢條件的完全匹配,相當於and

must_not:: 多個查詢條件的相反匹配,相當於not

should:: 至少有一個查詢條件匹配, 相當於or

這些引數可以分別繼承一個過濾條件或者一個過濾條件的陣列

案例:展示一個全文檢索的效果

首先查詢條件也會進行分詞

kama

chenyi

並集

案例:不要把條件分詞,要精確匹配

但是我們現有有一種需求我就是想查詢kama chenyi不要分詞,要精確匹配到

百度就類似於這樣

案例:把查詢結果進行高亮展示

<em>kama</em>這個標籤是預設的標籤,是可以自定義的進行替換的,比如我們可以替換成<span style="color:red">kama</span>,把這個輸出到網頁上,自然而然就是紅色的了。

9.聚合分析

案例:計算每個標籤tag下商品的數量

按標籤進行分組類似於 select count(*) from product group by tag;

termsterm有點類似,但terms允許指定多個匹配條件。 如果某個欄位指定了多個值,那麼文件需要一起去做匹配

error是報錯,但是這個語句是對的,這個報錯在ES2之前是沒有的,在ES5以後才有的,在5中fielddata=true 預設是false,以前都是true

group_by_tag是個名字隨意取

所以我們需要先執行下面的程式碼進行一下設定的修改:

再次執行一次

案例:對商品名稱裡面包含chenyi的,計算每個tag下商品的數量

案例:查詢商品名稱裡面包含chenyi的資料,並且按照tag進行分組,計算每個分組下的平均價格

案例:查詢商品名稱裡面包含chenyi的資料,並且按照tag進行分組,計算每個分組下的平均價格,按照平均價格進行降序排序

注意寫的位置

案例:查詢出producer裡面包含producer的資料,按照指定的價格區間進行分組,在每個組內再按tag進行分組,分完組以後再求每個組的平均價格,並且按照降序進行排序

range過濾允許我們按照指定範圍查詢一批資料

10.ES的隱藏性

ES是一個分散式的系統,裡面我們在使用的時候隱藏了複雜的分散式的機制

1)分片機制

插入資料的時候不是根據負載均衡來插入的,是根據一定的路由規則,比如我們就取雜湊值取模,

我們在建立一個index庫的時候,我們可以指定primary shard的數量,也可以指定replica的數量,如果不指定,那麼預設primary shard=5 replica=1 所以 replica shard=5,過了一段時間發現數據量很大,我們primary shard不夠用了,那麼這個時候想修改shard 的個數,能不能改成20個?答案:不能!!原來本應該插入到8的位置,結果插入到了9的位置,這樣計算查詢規則就錯了。所以主分片個數是不能修改的,但是副分片的個數是可以進行修改的。具體怎麼完成的那是ES內部的事情,我們先不用考慮。我們寫了段java的程式碼插入資料到主分片裡面去了。具體怎麼插入的,插入到哪個主分片裡面是不需要我們來管的。所以就是把這些功能給隱藏起來了。

如果真的遇見了這樣的事,再建一個庫,那個庫的分片是20,用程式碼查詢出來再匯入到這個庫中,只能用這個方法

總結:我們操作的時候很輕鬆的就把資料存入到我們的ES裡面了。存入的時候我們並不關心,資料存到哪個分片裡面去。

2)叢集的發現機制

我們做過一個實驗,一開始我們只啟動了一個ES的節點,這個時候這個ES的狀態是yellow,後來我們又啟動了一個ES節點,發現顏色變成了green,這說明,我們後面啟動的這個節點,也自動加入了這個叢集。那麼這個機制就是叢集的發現機制。對於我們也是隱藏起來了。我們沒必要知道

3)shard 會進行負載均衡

Hbase中如果你新加入了一個Hbase節點,不會自動的進行負載均衡,需要執行一個命令

但是ES不一樣。只要你加入了一個節點,會自動幫你進行負載均衡

11.ES叢集的擴容問題

擴容分為:垂直和水平擴容

我們之前的大資料技術都是分散式的部署在叢集上面的。如果我們的資源不夠用了,這個時候就涉及到了擴容,我們是垂直擴容還是水平擴容呢?

假設我們每個節點能儲存1T的資料,現在我們要儲存5T的資料,

垂直擴容就是把其中的一臺換了,換成效能更強的節點。有可能一臺節點就能存5T。

水平擴容就是新加伺服器直到能存下來5T的資料,我們一般都是用水平擴容,比如1T是1萬。5臺5萬,但是單臺5T的價錢可能是50萬。所以我們幾乎不太可能用這種方式。

但是可能那麼namenode節點可能是採用垂直擴容

12.對等式架構

在分散式的技術裡面。我們大多都是主從式架構

ES是對等式的架構。ES裡面也有master節點一說。但是我們不太關心。只需要在配置檔案中指定一下讓哪幾個節點有機會成為主節點。

ES中master的作用

1)管理叢集的元資料,比如說索引的建立,和刪除等等

2)叢集裡面master也是自動選舉的。

看到這裡有個疑問這不也是主從式架構麼?為什麼叫對等式架構呢?

HDFS是主從式架構,有namenode和datanode,我們無論是上傳資料也好還是下載資料也好都要跟namenode進行互動,互動完才能到datanode中,但是我們的ES無論上傳和下載資料也好,我們不需要跟master進行互動。節點之間的關係都是對等的,每個節點都可以進行接收請求和響應請求。

在ES中,我們開發好了java程式碼要跟ES進行互動。他會隨意找一臺節點,但是這臺節點不一定有我們要查詢的資料,但是我們不知道,ES節點是知道的,每個ES裡面都知道其他的資料存在哪ES的節點會自動幫你把請求發到要查詢資料的節點上。這樣就真的查詢出來了。而我們隨意找的這個節點叫做協調節點,真正資料存放的節點會把資料返回給協調節點。協調節點再給我們java的程式碼

每一個節點都可以接受和相應請求。如果隨機找的剛好是資料所在的節點,那麼這個節點即是協調節點又是響應節點。

13.ES的primary shard和replica shard

1)index可以包含多個type,同樣一個index下面也可以有多個shard

2)在ES裡面每個shard就是最小的一個工作單元,承載了部分資料

3)如果在ES叢集裡面增加或減少節點,shard會自動的實現負載均衡

4)primary shard樂意進行讀和寫,replica shard負責讀

5)primary shard在建立index的時候就固定了,不能修改了。

6)預設建立一個index的時候,primary shard的數量是5,replica的數量是1,也就是說預設情況下有10個shard,其中有5個primary shard,5個是replica shard

7)primary shard和自己的replica shard是不能在同一臺伺服器上的。

14.ES的容錯機制

1)master的選舉

2)replica的容錯

3)資料恢復

15.自動生成ID號

下圖是指定ID號的方式

下圖是自動生成ID號

16.version之悲觀鎖和樂觀鎖

悲觀鎖:很悲觀,自己操作的時候別的執行緒就不能進行操作。所以在電商的情況下體驗性很不好,但是不容易出錯

樂觀鎖:很樂觀,因為現在剩3件了,假設version號是5,A,B執行緒同時進行訪問操作,AB執行緒拿到的都是3件,version都是5,A執行緒先購買了一件就是3-1=2 ,然後A執行緒拿著2和version號5去更新資料,發現version是5就把3件更新為2件,同時version變成了6;然後B執行緒買了一件就是3-1=2 然後拿著2和version號5去更新,發現version號不匹配,此時重新獲取一下version號和僅剩的件數2,然後2-1=1,然後拿著1和version號6去更新資料,發現version對上了。此時更新成功。

17.用java實現對ES的增刪改查


  1. package com.aura.utils;

  2. import com.aura.dao.Dao;

  3. import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;

  4. import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;

  5. import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;

  6. import org.elasticsearch.action.delete.DeleteResponse;

  7. import org.elasticsearch.action.get.GetResponse;

  8. import org.elasticsearch.action.index.IndexResponse;

  9. import org.elasticsearch.action.search.SearchResponse;

  10. import org.elasticsearch.action.update.UpdateResponse;

  11. import org.elasticsearch.client.IndicesAdminClient;

  12. import org.elasticsearch.client.transport.TransportClient;

  13. import org.elasticsearch.common.settings.Settings;

  14. import org.elasticsearch.common.transport.InetSocketTransportAddress;

  15. import org.elasticsearch.common.xcontent.XContentBuilder;

  16. import org.elasticsearch.common.xcontent.XContentType;

  17. import org.elasticsearch.index.query.QueryBuilders;

  18. import org.elasticsearch.index.query.TermQueryBuilder;

  19. import org.elasticsearch.search.SearchHit;

  20. import org.elasticsearch.search.SearchHits;

  21. import org.elasticsearch.transport.client.PreBuiltTransportClient;

  22. import org.junit.Test;

  23. import java.io.IOException;

  24. import java.net.InetAddress;

  25. import java.net.UnknownHostException;

  26. import java.util.HashMap;

  27. import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

  28. public class EsUtils {

  29. //ES client

  30. private static TransportClient client;//獲取一個ES的客戶端物件叫client

  31. private static final String CLUSTER_NAME="elasticsearch";

  32. private static final String HOST_IP="127.0.0.1";

  33. private static final int TCP_PORT=9300;

  34. static Settings sttings=Settings.builder()

  35. .put("cluster.name",CLUSTER_NAME)//叢集名字CLUSTER_NAME

  36. .build();

  37. /**

  38. * 獲取client物件

  39. */

  40. public static TransportClient getCLient(){

  41. if(client == null){

  42. synchronized (TransportClient.class){

  43. try {

  44. client=new PreBuiltTransportClient(sttings)

  45. .addTransportAddress(

  46. new InetSocketTransportAddress(InetAddress.getByName(HOST_IP),TCP_PORT)#ES的master的主機名和埠號預設9300

  47. );

  48. } catch (UnknownHostException e) {

  49. e.printStackTrace();

  50. }

  51. }

  52. }

  53. System.out.println("連線成功"+client.toString());

  54. return client;

  55. }

  56. /**

  57. * 通過ES的客戶端物件,獲取索引管理物件

  58. * 獲取index admin 物件

  59. */

  60. public static IndicesAdminClient getIndicesAdminClient(){

  61. return getCLient().admin().indices();

  62. }

  63. /**

  64. * 建立一個 index 庫

  65. * 注意:es裡面索引庫的名稱 都需要小寫

  66. */

  67. public static boolean createIndex(String indexName){

  68. CreateIndexResponse response = getIndicesAdminClient()

  69. .prepareCreate(indexName.toLowerCase())#通過索引管理物件建立索引

  70. .setSettings(

  71. Settings.builder()

  72. .put("index.number_of_shards", 3)#分片個數

  73. .put("index.number_of_replicas", 2)#副分片個數

  74. ).execute().actionGet();

  75. return response.isShardsAcked();//返回boolean值,是否建立成功

  76. }

  77. /**

  78. * 建立index,對上面方法的優化

  79. * @param indexName

  80. * @param numberShards

  81. * @param numberreplicas

  82. * @return

  83. */

  84. public static boolean createIndex(String indexName,int numberShards,int numberreplicas){

  85. CreateIndexResponse response = getIndicesAdminClient()

  86. .prepareCreate(indexName.toLowerCase())

  87. .setSettings(

  88. Settings.builder()

  89. .put("index.number_of_shards", numberShards)

  90. .put("index.number_of_replicas", numberreplicas)

  91. ).execute().actionGet();

  92. return response.isShardsAcked();

  93. }

  94. /**

  95. * 刪除index

  96. *

  97. */

  98. public static boolean deleteIndex(String indexName){

  99. DeleteIndexResponse response = getIndicesAdminClient()

  100. .prepareDelete(indexName.toLowerCase())

  101. .execute().actionGet();

  102. return response.isAcknowledged();

  103. }

  104. /**

  105. * 設定mapping 建表語句

  106. * @param indexName

  107. * @param typeName

  108. * @param mappingStr

  109. * @return

  110. */

  111. public static boolean setIndexMapping(String indexName,String typeName,XContentBuilder mappingStr){

  112. IndicesAdminClient indicesAdminClient = getIndicesAdminClient();

  113. PutMappingResponse putMappingResponse = indicesAdminClient.preparePutMapping(indexName.toLowerCase())

  114. .setType(typeName)

  115. .setSource(mappingStr)

  116. .execute()

  117. .actionGet();

  118. return putMappingResponse.isAcknowledged();

  119. }

  120. @Test

  121. public void test1(){

  122. /**

  123. * PUT my_index/_mapping/type_1709x

  124. {

  125. "properties": {

  126. "user":{

  127. "type": "text"

  128. },

  129. "postDate":{

  130. "type": "date"

  131. },

  132. "message":{

  133. "type": "text"

  134. }

  135. }

  136. }

  137. *

  138. */

  139. try {

  140. XContentBuilder xContentBuilder = jsonBuilder().startObject()

  141. .startObject("properties")

  142. .startObject("user")

  143. .field("type", "text")

  144. .endObject()

  145. .startObject("postDate")

  146. .field("type", "date")

  147. .endObject()

  148. .startObject("message")

  149. .field("type", "text")

  150. .endObject()

  151. .endObject()

  152. .endObject();

  153. setIndexMapping("my_index","type_1709x",xContentBuilder);

  154. } catch (IOException e) {

  155. e.printStackTrace();

  156. }

  157. }

  158. /**

  159. * 往type裡面新增一條資料

  160. */

  161. @Test

  162. public void test4(){

  163. String json="{\n" +

  164. " \"user\":\"malaoshi\",\n" +

  165. " \"postdate\":\"2018-11-11\",\n" +

  166. " \"message\":\"haokaixin\"\n" +

  167. "}";

  168. TransportClient client = getCLient();

  169. IndexResponse indexResponse = client.prepareIndex("my_index", "type_1709x", "1")

  170. .setSource(json, XContentType.JSON)

  171. .get();

  172. System.out.println( indexResponse.status().getStatus());

  173. }

  174. /**

  175. * 往type裡面新增一條資料

  176. */

  177. @Test

  178. public void test5(){

  179. HashMap<String, String> json = new HashMap<String, String>();

  180. json.put("user","Xiao li");

  181. json.put("postdate","2017-12-12");

  182. json.put("message","Xiao li trying out ES");

  183. TransportClient client = getCLient();

  184. IndexResponse indexResponse = client.prepareIndex("my_index", "type_1709x", "2")

  185. .setSource(json, XContentType.JSON)

  186. .get();

  187. System.out.println(indexResponse.status().getStatus());

  188. }

  189. /**

  190. * 查詢資料

  191. */

  192. @Test

  193. public void test6(){

  194. TransportClient client = getCLient();

  195. GetResponse getFields = client.prepareGet("my_index", "type_1709x", "2").execute().actionGet();

  196. //{"postdate":"2017-12-12","message":"Xiao li trying out ES","user":"Xiao li"}

  197. System.out.println(getFields.getSourceAsString());

  198. //{postdate=2017-12-12, message=Xiao li trying out ES, user=Xiao li}

  199. System.out.println(getFields.getSourceAsMap());

  200. }

  201. /**

  202. * 修改資料

  203. */

  204. @Test

  205. public void test7(){

  206. HashMap<String, String> json = new HashMap<String, String>();

  207. json.put("user","xiao li");

  208. json.put("postdate","2017-11-11");

  209. json.put("message","xiao li trying out elasticsearch");

  210. TransportClient client = getCLient();

  211. UpdateResponse updateResponse = client.prepareUpdate("my_index", "type_1709x", "2")

  212. .setDoc(json)

  213. .execute().actionGet();

  214. System.out.println(updateResponse.status().getStatus());

  215. }

  216. /**

  217. * 刪除

  218. */

  219. @Test

  220. public void test8(){

  221. TransportClient client = getCLient();

  222. DeleteResponse deleteResponse = client.prepareDelete("my_index", "type_1709x", "2").execute().actionGet();

  223. System.out.println(deleteResponse.status().getStatus());

  224. }

  225. /**

  226. * 具有條件的查詢

  227. */

  228. @Test

  229. public void test9(){

  230. TransportClient client = getCLient();

  231. TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("user", "malaoshi");

  232. SearchResponse searchResponse = client.prepareSearch("my_index")

  233. .setTypes("type_1709x")

  234. .setQuery(termQueryBuilder)

  235. .execute().actionGet();

  236. SearchHits hits = searchResponse.getHits();

  237. System.out.println(hits.totalHits);

  238. for(SearchHit hit:hits){

  239. System.out.println(hit.getScore());

  240. System.out.println(hit.getSourceAsString());

  241. }

  242. }

  243. public static void setMapping(){

  244. try {

  245. XContentBuilder xContentBuilder1 = jsonBuilder().startObject()

  246. .startObject("properties")

  247. .startObject("id")

  248. .field("type", "long")

  249. .endObject()

  250. .startObject("title")

  251. .field("type", "text")

  252. .field("analyzer", "ik_max_word")

  253. .field("search_analyzer", "ik_max_word")

  254. .endObject()

  255. .startObject("content")

  256. .field("type", "text")

  257. .field("analyzer", "ik_max_word")

  258. .field("search_analyzer", "ik_max_word")

  259. .endObject()

  260. .startObject("url")

  261. .field("type", "keyword")

  262. .endObject()

  263. .startObject("reply")

  264. .field("type", "long")

  265. .endObject()

  266. .startObject("source")

  267. .field("type", "keyword")

  268. .endObject()

  269. .startObject("postDate")

  270. .field("type", "date")

  271. .field("format", "yyyy-MM-dd HH:mm:ss")

  272. .endObject()

  273. .endObject()

  274. .endObject();

  275. setIndexMapping("sportnews","news",xContentBuilder1);

  276. } catch (IOException e) {

  277. e.printStackTrace();

  278. }

  279. }

  280. public static void main(String[] args) {

  281. // createIndex("my_index",3,2);

  282. // deleteIndex("test1709");

  283. /**

  284. * 第一步:建立Index 庫

  285. */

  286. // createIndex("sportnews",3,1);

  287. /**

  288. * 第二步:建立表

  289. * 設定mapping

  290. */

  291. // setMapping();

  292. /**

  293. * 第三步:

  294. * 從MySQL匯入資料到ES

  295. */

  296. // Dao dao = new Dao();

  297. // dao.getConnection();

  298. // dao.mysqlToEs();

  299. }

  300. }

18.專案實戰

模仿百度文庫的效果。

1)首先用IDEA新建web maven專案

然後一直下一步就行了。

配置pom.xml檔案為如下所示


  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  4. <modelVersion>4.0.0</modelVersion>

  5. <groupId>jenrey</groupId>

  6. <artifactId>ES_project</artifactId>

  7. <version>1.0-SNAPSHOT</version>

  8. <packaging>war</packaging>

  9. <name>ES_project Maven Webapp</name>

  10. <!-- FIXME change it to the project's website -->

  11. <url>http://www.example.com</url>

  12. <properties>

  13. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

  14. <maven.compiler.source>1.7</maven.compiler.source>

  15. <maven.compiler.target>1.7</maven.compiler.target>

  16. </properties>

  17. <dependencies>

  18. <dependency>

  19. <groupId>junit</groupId>

  20. <artifactId>junit</artifactId>

  21. <version>4.12</version>

  22. <scope>test</scope>

  23. </dependency>

  24. <dependency>

  25. <groupId>javax.servlet</groupId>

  26. <artifactId>javax.servlet-api</artifactId>

  27. <version>3.1.0</version>

  28. <scope>provided</scope>

  29. </dependency>

  30. <dependency>

  31. <groupId>mysql</groupId>

  32. <artifactId>mysql-connector-java</artifactId>

  33. <version>5.1.6</version>

  34. </dependency>

  35. <dependency>

  36. <groupId>org.elasticsearch.client</groupId>

  37. <artifactId>transport</artifactId>

  38. <version>6.3.2</version>

  39. </dependency>

  40. </dependencies>

  41. <build>

  42. <finalName>ES_project</finalName>

  43. <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

  44. <plugins>

  45. <plugin>

  46. <artifactId>maven-clean-plugin</artifactId>

  47. <version>3.0.0</version>

  48. </plugin>

  49. <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->

  50. <plugin>

  51. <artifactId>maven-resources-plugin</artifactId>

  52. <version>3.0.2</version>

  53. </plugin>

  54. <plugin>

  55. <artifactId>maven-compiler-plugin</artifactId>

  56. <version>3.7.0</version>

  57. </plugin>

  58. <plugin>

  59. <artifactId>maven-surefire-plugin</artifactId>

  60. <version>2.20.1</version>

  61. </plugin>

  62. <plugin>

  63. <artifactId>maven-war-plugin</artifactId>

  64. <version>3.2.0</version>

  65. </plugin>

  66. <plugin>

  67. <artifactId>maven-install-plugin</artifactId>

  68. <version>2.5.2</version>

  69. </plugin>

  70. <plugin>

  71. <artifactId>maven-deploy-plugin</artifactId>

  72. <version>2.8.2</version>

  73. </plugin>

  74. </plugins>

  75. </pluginManagement>

  76. </build>

  77. </project>

啟動專案:

出現上圖的No artifacts marked for deployment的警告並出現如下幾張圖所示的效果。

這時候不要慌!!!按照下圖所示進行操作,再次開啟配置選單

新增xxxxxxx:war exploded

Tomcat部署中war與war exploded區別

  • war模式:即釋出模式,將Web工程以war包的形式上傳到伺服器。
  • war exploded模式:將Web工程以當前資料夾的位置關係上傳到伺服器。

【注】

  1. 此模式直接把資料夾、jsp頁面等相關檔案移動到Tomcat部署資料夾裡進行載入部署。因此此模式支援熱部署。
  2. 使用熱部署,需要對其他選項進行設定

然後儲存,然後再按照下圖修改,應用,確定

2)程式碼開發階段

index.jsp程式碼


  1. <%@ page contentType="text/html; charset=UTF-8" language="java" %>

  2. <html>

  3. <title>新聞搜尋</title>

  4. <style type="text/css">

  5. body{

  6. margin: 0 auto;

  7. }

  8. .box{

  9. width: 720px;

  10. height: 480px;

  11. margin: 30px auto;

  12. border: 1px solid #cccccc;

  13. }

  14. .box h1{

  15. color: red;

  16. text-align: center;

  17. margin-top: 50px;

  18. }

  19. .searchbox{

  20. width: 80%;

  21. height: 30px;

  22. border: 1px solid #cccccc;

  23. margin: 60px auto;

  24. }

  25. .searchbox input[type="text"]{

  26. height: 30px;

  27. width: 85%;

  28. font-size: 15px;

  29. border: none;

  30. outline: none;

  31. }

  32. .searchbox input[type="submit"]{

  33. height: 30px;

  34. width: 14%;

  35. background-color: blue;

  36. color: white;

  37. }

  38. </style>

  39. <body>

  40. <div class="box">

  41. <h1>1709新聞搜尋</h1>

  42. <div class="searchbox">

  43. <form action="SearchNews" method="post">

  44. <input type="text" name="query"/>

  45. <input type="submit" value="搜尋一下" />

  46. </form>

  47. </div>

  48. </div>

  49. </body>

  50. </html>

上述程式碼寫完的網頁前端效果如下

result.jsp頁面程式碼


  1. <%@ page import="java.util.ArrayList" %>

  2. <%@ page import="java.util.Map" %>

  3. <%@ page import="java.util.Iterator" %><%--

  4. Created by IntelliJ IDEA.

  5. User: Administrator

  6. Date: 2018/2/2

  7. Time: 10:10

  8. To change this template use File | Settings | File Templates.

  9. --%>

  10. <%@ page contentType="text/html;charset=UTF-8" language="java" %>

  11. <html>

  12. <head>

  13. <title>結果頁面</title>

  14. </head>

  15. <style type="text/css">

  16. body {

  17. margin: 0;

  18. padding: 0;

  19. }

  20. .result_search{

  21. width:100%;

  22. height:60px;

  23. padding-left:30px;

  24. padding-top:20px;

  25. padding-bottom:20px;

  26. border:1px solid #cccccc;

  27. }

  28. .logo {

  29. float: left;

  30. width: 100px;

  31. }

  32. .logo a:link, .logo a:visited {

  33. text-decoration: none;

  34. color: #ff2b3b;

  35. }

  36. .searchbox {

  37. width: 500px;

  38. float: left;

  39. margin-top: 20px;

  40. margin-left: 30px;

  41. border: 1px solid #cccccc;

  42. height: 30px;

  43. background-color: #ffffff;

  44. float: left;

  45. }

  46. .searchbox input[type="text"]{

  47. height: 30px;

  48. width: 85%;

  49. font-size: 18px;

  50. border: none;

  51. outline: none;

  52. }

  53. .searchbox input[type="submit"]{

  54. height: 30px;

  55. width: auto;

  56. height:30px;

  57. width: 14%;

  58. margin: 0px;

  59. background-color: #1426ff;

  60. color: #f8fdff;

  61. }

  62. .result_info {

  63. padding-left: 50px;

  64. }

  65. .result_info span {

  66. color: #ff0000;

  67. }

  68. .newsist {

  69. width: 700px;

  70. margin-top: 10px;

  71. margin-left: 30px;

  72. height: auto;

  73. min-height: 500px;

  74. position: relative;

  75. }

  76. .news {

  77. margin-top: 15px;

  78. }

  79. .news h4 {

  80. padding-left: 20px;

  81. color: #1c00ce;

  82. margin: 0;

  83. }

  84. .news h4 a:link, .news h3 a:visited {

  85. text-decoration: none;

  86. color: #1c00ce;

  87. }

  88. .news h4 a:hover {

  89. text-decoration: underline;

  90. }

  91. .news p {

  92. margin: 10px;

  93. line-height: 1.5;

  94. padding-left: 10px;

  95. font-size: 12px;

  96. color: black;

  97. }

  98. #page {

  99. width: 90%;

  100. height: 40px;

  101. margin: 0 auto;

  102. }

  103. ul {

  104. list-style: none;

  105. height: 30px;

  106. }

  107. ul li {

  108. float: left;

  109. width: 50px;

  110. padding: 0;

  111. margin: 0;

  112. font-size: 12px;

  113. }

  114. ul li a:link, ul li a:visited {

  115. text-decoration: none;

  116. display: block;

  117. line-height: 18px;

  118. color: #004080;

  119. }

  120. </style>

  121. <body>

  122. <%

  123. String queryback=(String)request.getAttribute("queryback");

  124. ArrayList<Map<String,Object>> newslist=(ArrayList<Map<String,Object>>)request.getAttribute("newsist");

  125. String count=(String)request.getAttribute("count");

  126. int pages=Integer.parseInt(count)/10 +1;

  127. pages=pages>10?10:pages;

  128. %>

  129. <div class="result_search">

  130. <div class="logo">

  131. <h2><a href="index.jsp">新聞搜尋</a></h2>

  132. </div>

  133. <div class="searchbox">

  134. <form class="resultform" action="/SearchNews" method="post">

  135. <input type="text" value="<%=queryback%>" name="query" />

  136. <input type="submit" value="搜尋一下" />

  137. </form>

  138. </div>

  139. </div>

  140. <h5 class="result_info">共搜尋到<span>1111</span>條結果,耗時<span>11</span>秒</h5>

  141. <div class="newsist">

  142. <%

  143. if(newslist.size() > 0){

  144. Iterator<Map<String, Object>> iterator = newslist.iterator();

  145. while (iterator.hasNext()){

  146. Map<String, Object> news = iterator.next();

  147. Object url = news.get("url");

  148. String title = (String) news.get("title");

  149. String content =(String) news.get("content");

  150. content=content.length()>300?content.substring(0,300)+"...":content;

  151. %>

  152. <div class="news">

  153. <h4>

  154. <a href="<%=url%>"><%=title%> </a>

  155. <p><%=content%></p>

  156. </h4>

  157. </div>

  158. <%

  159. }

  160. }

  161. %>

  162. </div>

  163. <div id="page">

  164. <ul>

  165. <%

  166. for ( int i=1;i<=pages;i++){

  167. %>

  168. <li><a href="/SearchNews?query=<%=queryback%>&pageNum=<%=i%>">第<%=i%>頁</a></li>

  169. <%

  170. }

  171. %>

  172. <li><a href="xxx">共<%=pages%>頁</a></li>

  173. </ul>

  174. </div>

  175. </body>

  176. </html>

上面是終極程式碼,初級程式碼的效果圖如下

3)導maven包