自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

超詳細(xì)的Elasticsearch高性能優(yōu)化實(shí)踐

原創(chuàng)
開發(fā) 架構(gòu)
之前分享的一篇《掌握它才說明你真正懂 Elasticsearch》相信讓大家對(duì) ES 的原理都有所了解,這篇將從 ES 的 API 應(yīng)用測(cè)試,性能優(yōu)化,開發(fā)使用等方面展開,深入學(xué)習(xí) ES。

【51CTO.com原創(chuàng)稿件】之前分享的一篇《掌握它才說明你真正懂 Elasticsearch》相信讓大家對(duì) ES 的原理都有所了解,這篇將從 ES 的 API 應(yīng)用測(cè)試,性能優(yōu)化,開發(fā)使用等方面展開,深入學(xué)習(xí) ES。

ES 性能調(diào)優(yōu)

ES 的默認(rèn)配置,是綜合了數(shù)據(jù)可靠性、寫入速度、搜索實(shí)時(shí)性等因素。實(shí)際使用時(shí),我們需要根據(jù)公司要求,進(jìn)行偏向性的優(yōu)化。

寫優(yōu)化

假設(shè)我們的應(yīng)用場(chǎng)景要求是,每秒 300 萬(wàn)的寫入速度,每條 500 字節(jié)左右。

針對(duì)這種對(duì)于搜索性能要求不高,但是對(duì)寫入要求較高的場(chǎng)景,我們需要盡可能的選擇恰當(dāng)寫優(yōu)化策略。

綜合來說,可以考慮以下幾個(gè)方面來提升寫索引的性能:

  • 加大 Translog Flush ,目的是降低 Iops、Writeblock。
  • 增加 Index Refresh 間隔,目的是減少 Segment Merge 的次數(shù)。
  • 調(diào)整 Bulk 線程池和隊(duì)列。
  • 優(yōu)化節(jié)點(diǎn)間的任務(wù)分布。
  • 優(yōu)化 Lucene 層的索引建立,目的是降低 CPU 及 IO。

①批量提交

ES 提供了 Bulk API 支持批量操作,當(dāng)我們有大量的寫任務(wù)時(shí),可以使用 Bulk 來進(jìn)行批量寫入。

每次提交的數(shù)據(jù)量為多少時(shí),能達(dá)到很好性能,主要受到文件大小、網(wǎng)絡(luò)情況、數(shù)據(jù)類型、集群狀態(tài)等因素影響。

通用的策略如下:Bulk 默認(rèn)設(shè)置批量提交的數(shù)據(jù)量不能超過 100M。數(shù)據(jù)條數(shù)一般是根據(jù)文檔的大小和服務(wù)器性能而定的,但是單次批處理的數(shù)據(jù)大小應(yīng)從 5MB~15MB 逐漸增加。

我們可以跟著,感受一下 Bulk 接口,如下所示:

  1. $ vi request 
  2. $ cat request 
  3. "index" : { "_index" : "chandler","_type""test""_id" : "1" } } 
  4. "name" : "錢丁君","age""18" } 
  5. $ curl -s -H "Content-Type: application/json" -XPOST localhost:9200/_bulk --data-binary @request; echo 
  6. {"took":214,"errors":false,"items":[{"index":{"_index":"chandler","_type":"test","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1,"status":201}}]} 
  7. $ curl -XGET localhost:9200/chandler/test/1?pretty 
  8.   "_index" : "chandler"
  9.   "_type" : "test"
  10.   "_id" : "1"
  11.   "_version" : 1, 
  12.   "found" : true
  13.   "_source" : { 
  14.     "name" : "錢丁君"
  15.     "age" : "18" 
  16.   } 

Bulk 不支持 Gget 操作,因?yàn)闆]什么用處。

②優(yōu)化存儲(chǔ)設(shè)備

ES 是一種密集使用磁盤的應(yīng)用,在段合并的時(shí)候會(huì)頻繁操作磁盤,所以對(duì)磁盤要求較高,當(dāng)磁盤速度提升之后,集群的整體性能會(huì)大幅度提高。

磁盤的選擇,提供以下幾點(diǎn)建議:

  • 使用固態(tài)硬盤(Solid State Disk)替代機(jī)械硬盤。SSD 與機(jī)械磁盤相比,具有高效的讀寫速度和穩(wěn)定性。
  • 使用 RAID 0。RAID 0 條帶化存儲(chǔ),可以提升磁盤讀寫效率。
  • 在 ES 的服務(wù)器上掛載多塊硬盤。使用多塊硬盤同時(shí)進(jìn)行讀寫操作提升效率,在配置文件 ES 中設(shè)置多個(gè)存儲(chǔ)路徑,如下所示:
  1. path.data:/path/to/data1,/path/to/data2。 

避免使用 NFS(Network File System)等遠(yuǎn)程存儲(chǔ)設(shè)備,網(wǎng)絡(luò)的延遲對(duì)性能的影響是很大的。

③合理使用合并

Lucene 以段的形式存儲(chǔ)數(shù)據(jù)。當(dāng)有新的數(shù)據(jù)寫入索引時(shí),Lucene 就會(huì)自動(dòng)創(chuàng)建一個(gè)新的段。

隨著數(shù)據(jù)量的變化,段的數(shù)量會(huì)越來越多,消耗的多文件句柄數(shù)及 CPU 就越多,查詢效率就會(huì)下降。

由于 Lucene 段合并的計(jì)算量龐大,會(huì)消耗大量的 I/O,所以 ES 默認(rèn)采用較保守的策略,讓后臺(tái)定期進(jìn)行段合并,如下所述:

  • 索引寫入效率下降:當(dāng)段合并的速度落后于索引寫入的速度時(shí),ES 會(huì)把索引的線程數(shù)量減少到 1。

這樣可以避免出現(xiàn)堆積的段數(shù)量爆發(fā),同時(shí)在日志中打印出“now throttling indexing”INFO 級(jí)別的“警告”信息。

  • 提升段合并速度:ES 默認(rèn)對(duì)段合并的速度是 20m/s,如果使用了 SSD,我們可以通過以下的命令將這個(gè)合并的速度增加到 100m/s。
    1. PUT /_cluster/settings 
    2.     "persistent" : { 
    3.         "indices.store.throttle.max_bytes_per_sec" : "100mb" 
    4.     } 

④減少 Refresh 的次數(shù)

Lucene 在新增數(shù)據(jù)時(shí),采用了延遲寫入的策略,默認(rèn)情況下索引的 refresh_interval 為 1 秒。

Lucene 將待寫入的數(shù)據(jù)先寫到內(nèi)存中,超過 1 秒(默認(rèn))時(shí)就會(huì)觸發(fā)一次 Refresh,然后 Refresh 會(huì)把內(nèi)存中的的數(shù)據(jù)刷新到操作系統(tǒng)的文件緩存系統(tǒng)中。

如果我們對(duì)搜索的實(shí)效性要求不高,可以將 Refresh 周期延長(zhǎng),例如 30 秒。

這樣還可以有效地減少段刷新次數(shù),但這同時(shí)意味著需要消耗更多的Heap內(nèi)存。

如下所示:

  1. index.refresh_interval:30s 

⑤加大 Flush 設(shè)置

Flush 的主要目的是把文件緩存系統(tǒng)中的段持久化到硬盤,當(dāng) Translog 的數(shù)據(jù)量達(dá)到 512MB 或者 30 分鐘時(shí),會(huì)觸發(fā)一次 Flush。

index.translog.flush_threshold_size 參數(shù)的默認(rèn)值是 512MB,我們進(jìn)行修改。

增加參數(shù)值意味著文件緩存系統(tǒng)中可能需要存儲(chǔ)更多的數(shù)據(jù),所以我們需要為操作系統(tǒng)的文件緩存系統(tǒng)留下足夠的空間。

⑥減少副本的數(shù)量

ES 為了保證集群的可用性,提供了 Replicas(副本)支持,然而每個(gè)副本也會(huì)執(zhí)行分析、索引及可能的合并過程,所以 Replicas 的數(shù)量會(huì)嚴(yán)重影響寫索引的效率。

當(dāng)寫索引時(shí),需要把寫入的數(shù)據(jù)都同步到副本節(jié)點(diǎn),副本節(jié)點(diǎn)越多,寫索引的效率就越慢。

如果我們需要大批量進(jìn)行寫入操作,可以先禁止 Replica 復(fù)制,設(shè)置 index.number_of_replicas: 0 關(guān)閉副本。在寫入完成后,Replica 修改回正常的狀態(tài)。

讀優(yōu)化

①避免大結(jié)果集和深翻

在上一篇講到了集群中的查詢流程,例如,要查詢從 from 開始的 size 條數(shù)據(jù),則需要在每個(gè)分片中查詢打分排名在前面的 from+size 條數(shù)據(jù)。

協(xié)同節(jié)點(diǎn)將收集到的n×(from+size)條數(shù)據(jù)聚合,再進(jìn)行一次排序,然后從 from+size 開始返回 size 條數(shù)據(jù)。

當(dāng) from、size 或者 n 中有一個(gè)值很大的時(shí)候,需要參加排序的數(shù)量也會(huì)增長(zhǎng),這樣的查詢會(huì)消耗很多 CPU 資源,從而導(dǎo)致效率的降低。

為了提升查詢效率,ES 提供了 Scroll 和 Scroll-Scan 這兩種查詢模式。

Scroll:是為檢索大量的結(jié)果而設(shè)計(jì)的。例如,我們需要查詢 1~100 頁(yè)的數(shù)據(jù),每頁(yè) 100 條數(shù)據(jù)。

如果使用 Search 查詢:每次都需要在每個(gè)分片上查詢得分較高的 from+100 條數(shù)據(jù),然后協(xié)同節(jié)點(diǎn)把收集到的 n×(from+100)條數(shù)據(jù)聚合起來再進(jìn)行一次排序。

每次返回 from+1 開始的 100 條數(shù)據(jù),并且要重復(fù)執(zhí)行 100 次。

如果使用 Scroll 查詢:在各個(gè)分片上查詢 10000 條數(shù)據(jù),協(xié)同節(jié)點(diǎn)聚合 n×10000 條數(shù)據(jù)進(jìn)行合并、排序,并將排名前 10000 的結(jié)果快照起來。這樣做的好處是減少了查詢和排序的次數(shù)。

Scroll 初始查詢的命令是:

  1. $ vim scroll 
  2. $ cat scroll 
  3.     "query": { 
  4.         "match": { 
  5.             "name""錢丁君" 
  6.         } 
  7.     }, 
  8.     "size":20 
  9. $ curl -s -H "Content-Type: application/json; charset=UTF-8" -XGET localhost:9200/chandler/test/_search?scroll=2m --data-binary @scroll; echo 
  10. {"_scroll_id":"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAAGFlB6Y3QtNk9oUmdpc09Tb21rX2NXQXcAAAAAAAAABxZQemN0LTZPaFJnaXNPU29ta19jV0F3AAAAAAAAAAgWUHpjdC02T2hSZ2lzT1NvbWtfY1dBdwAAAAAAAAAJFlB6Y3QtNk9oUmdpc09Tb21rX2NXQXcAAAAAAAAAChZQemN0LTZPaFJnaXNPU29ta19jV0F3","took":14,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":1,"max_score":0.8630463,"hits":[{"_index":"chandler","_type":"test","_id":"1","_score":0.8630463,"_source":{ "name" : "錢丁君","age""18" }}]}} 

以上查詢語(yǔ)句的含義是,在 chandler 索引的 test type 里查詢字段 name 包含“錢丁君”的數(shù)據(jù)。

scroll=2m 表示下次請(qǐng)求的時(shí)間不能超過 2 分鐘,size 表示這次和后續(xù)的每次請(qǐng)求一次返回的數(shù)據(jù)條數(shù)。

在這次查詢的結(jié)果中除了返回了查詢到的結(jié)果,還返回了一個(gè) scroll_id,可以把它作為下次請(qǐng)求的參數(shù)。

再次請(qǐng)求的命令,如下所示:

因?yàn)檫@次并沒有到分片里查詢數(shù)據(jù),而是直接在生成的快照里面以游標(biāo)的形式獲取數(shù)據(jù)。

所以這次查詢并沒有包含 index 和 type,也沒有查詢條件:

  1. "scroll": "2m":指本次請(qǐng)求的時(shí)間不能超過 2 分鐘。
  2. scroll_id:是上次查詢時(shí)返回的 scroll_id。

Scroll-Scan:Scroll 是先做一次初始化搜索把所有符合搜索條件的結(jié)果緩存起來生成一個(gè)快照,然后持續(xù)地、批量地從快照里拉取數(shù)據(jù)直到?jīng)]有數(shù)據(jù)剩下。

而這時(shí)對(duì)索引數(shù)據(jù)的插入、刪除、更新都不會(huì)影響遍歷結(jié)果,因此 Scroll 并不適合用來做實(shí)時(shí)搜索。

其思路和使用方式與 Scroll 非常相似,但是 Scroll-Scan 關(guān)閉了 Scroll 中最耗時(shí)的文本相似度計(jì)算和排序,使得性能更加高效。

為了使用 Scroll-Scan,需要執(zhí)行一個(gè)初始化搜索請(qǐng)求,將 search_type 設(shè)置成 Scan,告訴 ES 集群不需要文本相似計(jì)算和排序,只是按照數(shù)據(jù)在索引中順序返回結(jié)果集:

  1. $ vi scroll 
  2. $ cat scroll 
  3.     "query": { 
  4.         "match": { 
  5.             "name""錢丁君" 
  6.         } 
  7.     }, 
  8.     "size":20, 
  9.     "sort": [ 
  10.       "_doc" 
  11.     ] 
  12. $ curl -H "Content-Type: application/json; charset=UTF-8" -XGET 'localhost:9200/chandler/test/_search?scroll=2m&pretty=true' --data-binary @scroll 
  13.   "_scroll_id" : "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAABWFlB6Y3QtNk9oUmdpc09Tb21rX2NXQXcAAAAAAAAAVxZQemN0LTZPaFJnaXNPU29ta19jV0F3AAAAAAAAAFgWUHpjdC02T2hSZ2lzT1NvbWtfY1dBdwAAAAAAAABZFlB6Y3QtNk9oUmdpc09Tb21rX2NXQXcAAAAAAAAAWhZQemN0LTZPaFJnaXNPU29ta19jV0F3"
  14.   "took" : 3, 
  15.   "timed_out" : false
  16.   "_shards" : { 
  17.     "total" : 5, 
  18.     "successful" : 5, 
  19.     "skipped" : 0, 
  20.     "failed" : 0 
  21.   }, 
  22.   "hits" : { 
  23.     "total" : 1, 
  24.     "max_score" : null
  25.     "hits" : [ 
  26.       { 
  27.         "_index" : "chandler"
  28.         "_type" : "test"
  29.         "_id" : "1"
  30.         "_score" : null
  31.         "_source" : { 
  32.           "name" : "錢丁君"
  33.           "age" : "18" 
  34.         }, 
  35.         "sort" : [ 
  36.           0 
  37.         ] 
  38.       } 
  39.     ] 
  40.   } 

注意:Elasticsearch 2.1.0 版本之后移除了 search_type=scan,使用 "sort": [ "_doc"] 進(jìn)行代替。

  • Scroll 和 Scroll-Scan 有一些差別,如下所示:
  • Scroll-Scan不進(jìn)行文本相似度計(jì)算,不排序,按照索引中的數(shù)據(jù)順序返回。
  • Scroll-Scan 不支持聚合操作。

Scroll-Scan 的參數(shù) Size 代表著每個(gè)分片上的請(qǐng)求的結(jié)果數(shù)量,每次返回 n×size 條數(shù)據(jù)。而 Scroll 每次返回 size 條數(shù)據(jù)。

②選擇合適的路由

ES 中所謂的路由和 IP 網(wǎng)絡(luò)不同,是一個(gè)類似于 Tag 的東西。在創(chuàng)建文檔的時(shí)候,可以通過字段為文檔增加一個(gè)路由屬性的 Tag。在多分片的 ES 集群中,對(duì)搜索的查詢大致分為如下兩種。

ES 內(nèi)在機(jī)制決定了擁有相同路由屬性的文檔,一定會(huì)被分配到同一個(gè)分片上,無論是主分片還是副本。

查詢時(shí)可以根據(jù) Routing 信息,直接定位到目標(biāo)分片,避免查詢所有的分片,再經(jīng)過協(xié)調(diào)節(jié)點(diǎn)二次排序。

如圖 1 所示:

圖 1

如果在查詢條件中不包含 Routing,在查詢時(shí)就遍歷所有分片,整個(gè)查詢主要分為 Scatter、Gather 兩個(gè)過程:

  • Scatter(分發(fā)):請(qǐng)求到達(dá)協(xié)調(diào)節(jié)點(diǎn)之后,協(xié)調(diào)節(jié)點(diǎn)將查詢請(qǐng)求分發(fā)給每個(gè)分片。
  • Gather(聚合):協(xié)調(diào)點(diǎn)在每個(gè)分片上完成搜索,再將搜索到的結(jié)果集進(jìn)行排序,將結(jié)果數(shù)據(jù)返回給用戶。

如圖 2 所示:

圖 2

通過對(duì)比上述兩種查詢流程,我們不難發(fā)現(xiàn),使用 Routing 信息查找的效率很高,避免了多余的查詢。

所以我們?cè)谠O(shè)計(jì) Elasticsearch Mapping 時(shí)要合理地利用 Routing 信息,來提升查詢的效率。

例如,在大型的本地分類網(wǎng)站中,可以將城市 ID 作為 Routing 的條件,讓同一個(gè)城市的數(shù)據(jù)落在相同的分片中。

默認(rèn)的公式如下:

  1. shard = hash(routing)%number_of_primary_shards 

不過需要注意的是,根據(jù)城市 ID 進(jìn)行分片時(shí),也會(huì)容易出現(xiàn)分片不均勻的情況。

例如,大型城市的數(shù)據(jù)過多,而小城市的數(shù)據(jù)太少,導(dǎo)致分片之間的數(shù)據(jù)量差異很大。

這時(shí)就可以進(jìn)行必要的調(diào)整,比如把多個(gè)小城市的數(shù)據(jù)合并到一個(gè)分片上,把大城市的數(shù)據(jù)按區(qū)域進(jìn)行拆分到不同分配。

③SearchType

在 Scatter、Gather 的過程中,節(jié)點(diǎn)間的數(shù)據(jù)傳輸和打分(SearchType),可以根據(jù)不同的場(chǎng)景選擇。

如下所示:

  • QUERY_THEN_FETCH:ES 默認(rèn)的搜索方式。先向所有的分片發(fā)請(qǐng)求,各分片只返回文檔的相似度得分和文檔的 ID,然后協(xié)調(diào)節(jié)點(diǎn)按照各分片返回的分?jǐn)?shù)進(jìn)行重新排序和排名,再取出需要返回給客戶端的 Size 個(gè)文檔 ID。

第 2 步,在相關(guān)的分片中取出文檔的詳細(xì)信息并返回給用戶。

  • QUERY_AND_FETCH:協(xié)調(diào)節(jié)點(diǎn)向所有分片發(fā)送查詢請(qǐng)求,各分片將文檔的相似度得分和文檔的詳細(xì)信息一起返回。

然后,協(xié)調(diào)節(jié)點(diǎn)進(jìn)行重新排序,再取出需要返回給客戶端的數(shù)據(jù),將其返回給客戶端。由于只需要在分片中查詢一次,所以性能很好。

  • DFS_QUERY_THEN_FETCH:與 QUERY_THEN_FETCH 類似,但它包含一個(gè)額外的階段:在初始查詢中執(zhí)行全局的詞頻計(jì)算,以使得更精確地打分,從而讓查詢結(jié)果更相關(guān)。

QUERY_THEN_FETCH 使用的是分片內(nèi)部的詞頻信息,而 DFS_QUERY_THEN_FETCH 使用訪問公共的詞頻信息,所以相比 QUERY_THEN_FETCH 性能更低。

  • DFS_QUERY_AND_FETCH:與 QUERY_AND_FETCH 類似,不過使用的是全局的詞頻。

④定期刪除

由于在 Lucene 中段具有不變性,每次進(jìn)行刪除操作后不會(huì)立即從硬盤中進(jìn)行實(shí)際的刪除,而是產(chǎn)生一個(gè) .del 文件記錄刪除動(dòng)作。

隨著刪除操作的增長(zhǎng),.del 文件會(huì)越來也多。當(dāng)我們進(jìn)行查詢操作的時(shí)候,被刪除的數(shù)據(jù)還會(huì)參與檢索中,然后根據(jù) .del 文件進(jìn)行過濾。.del 文件越多,查詢過濾過程越長(zhǎng),進(jìn)而影響查詢的效率。

當(dāng)機(jī)器空閑時(shí),我們可以通過如下命令刪除文件,來提升查詢的效率:

  1. $ curl -XPOST localhost:9200/chandler/_forcemerge?only_expunge_deletes=true 
  2. {"_shards":{"total":10,"successful":5,"failed":0}} 

定期對(duì)不再更新的索引做 optimize (ES 2.0 以后更改為 Force Merge API)。

這 Optimze 的實(shí)質(zhì)是對(duì) Segment File 強(qiáng)制做合并,可以節(jié)省大量的 Segment Memory。

堆大小的設(shè)置

ES 默認(rèn)安裝后設(shè)置的內(nèi)存是 1GB,對(duì)于任何一個(gè)現(xiàn)實(shí)業(yè)務(wù)來說,這個(gè)設(shè)置都太小了。

如果是通過解壓安裝的 ES,則在 ES 安裝文件中包含一個(gè) jvm.option 文件,添加如下命令來設(shè)置 ES 的堆大?。?/p>

  1. -Xms10g 
  2. -Xmx10g 

Xms 表示堆的初始大小,Xmx 表示可分配的內(nèi)存,都是 10GB。

確保 Xmx 和 Xms 的大小是相同的,其目的是為了能夠在 Java 垃圾回收機(jī)制清理完堆區(qū)后不需要重新分隔計(jì)算堆區(qū)的大小而浪費(fèi)資源,可以減輕伸縮堆大小帶來的壓力。

也可以通過設(shè)置環(huán)境變量的方式設(shè)置堆的大小。服務(wù)進(jìn)程在啟動(dòng)時(shí)候會(huì)讀取這個(gè)變量,并相應(yīng)的設(shè)置堆的大小。比如:

  1. export ES_HEAP_SIEZE=10g 

也可以通過命令行參數(shù)的形式,在程序啟動(dòng)的時(shí)候把內(nèi)存大小傳遞給 ES,如下所示:

  1. ./bin/elasticsearch -Xmx10g -Xms10g 

這種設(shè)置方式是一次性的,在每次啟動(dòng) ES 時(shí)都需要添加。

假設(shè)你有一個(gè) 64G 內(nèi)存的機(jī)器,按照正常思維思考,你可能會(huì)認(rèn)為把 64G 內(nèi)存都給 ES 比較好,但現(xiàn)實(shí)是這樣嗎, 越大越好?雖然內(nèi)存對(duì) ES 來說是非常重要的,但是答案是否定的!

因?yàn)?ES 堆內(nèi)存的分配需要滿足以下兩個(gè)原則:

  • 不要超過物理內(nèi)存的 50%:Lucene 的設(shè)計(jì)目的是把底層 OS 里的數(shù)據(jù)緩存到內(nèi)存中。

Lucene 的段是分別存儲(chǔ)到單個(gè)文件中的,這些文件都是不會(huì)變化的,所以很利于緩存,同時(shí)操作系統(tǒng)也會(huì)把這些段文件緩存起來,以便更快的訪問。

如果我們?cè)O(shè)置的堆內(nèi)存過大,Lucene 可用的內(nèi)存將會(huì)減少,就會(huì)嚴(yán)重影響降低 Lucene 的全文本查詢性能。

  • 堆內(nèi)存的大小不要超過 32GB:在 Java 中,所有對(duì)象都分配在堆上,然后有一個(gè) Klass Pointer 指針指向它的類元數(shù)據(jù)。

這個(gè)指針在 64 位的操作系統(tǒng)上為 64 位,64 位的操作系統(tǒng)可以使用更多的內(nèi)存(2^64)。在 32 位的系統(tǒng)上為 32 位,32 位的操作系統(tǒng)的尋址空間為 4GB(2^32)。

但是 64 位的指針意味著更大的浪費(fèi),因?yàn)槟愕闹羔槺旧泶罅?。浪費(fèi)內(nèi)存不算,更糟糕的是,更大的指針在主內(nèi)存和緩存器(例如 LLC, L1等)之間移動(dòng)數(shù)據(jù)的時(shí)候,會(huì)占用更多的帶寬。

Java 使用內(nèi)存指針壓縮(Compressed Oops)技術(shù)來解決這個(gè)問題。它的指針不再表示對(duì)象在內(nèi)存中的精確位置,而是表示偏移量。

這意味著 32 位的指針可以引用 4GB 個(gè) Byte,而不是 4GB 個(gè) bit。也就是說,當(dāng)堆內(nèi)存為 32GB 的物理內(nèi)存時(shí),也可以用 32 位的指針表示。

不過,在越過那個(gè)神奇的邊界 32GB 時(shí),指針就會(huì)變?yōu)槠胀▽?duì)象的指針,每個(gè)對(duì)象的指針都變長(zhǎng)了,就會(huì)浪費(fèi)更多的內(nèi)存,降低了 CPU 的性能,還要讓 GC 應(yīng)對(duì)更大的內(nèi)存。

事實(shí)上,當(dāng)內(nèi)存到達(dá) 40~40GB 時(shí),有效的內(nèi)存才相當(dāng)于內(nèi)存對(duì)象指針壓縮技術(shù)時(shí)的 32GB 內(nèi)存。

所以即便你有足夠的內(nèi)存,也盡量不要超過 32G,比如我們可以設(shè)置為 31GB:

  1. -Xms31g 
  2. -Xmx31g 

32GB 是 ES 一個(gè)內(nèi)存設(shè)置限制,那如果你的機(jī)器有很大的內(nèi)存怎么辦呢?現(xiàn)在的機(jī)器內(nèi)存普遍增長(zhǎng),甚至可以看到有 300-500GB 內(nèi)存的機(jī)器。

這時(shí)我們需要根據(jù)業(yè)務(wù)場(chǎng)景,進(jìn)行恰當(dāng)內(nèi)存的分配:

  • 業(yè)務(wù)場(chǎng)景是以全文檢索為主:依然可以給 ES 分配小于 32GB 的堆內(nèi)存,剩下的交給 Lucene 用作操作系統(tǒng)的文件系統(tǒng)緩存,所有的 Segment 都緩存起來,會(huì)加快全文檢索。
  • 業(yè)務(wù)場(chǎng)景中有很多的排序和聚合:我們可以考慮一臺(tái)機(jī)器上創(chuàng)建兩個(gè)或者更多 ES 節(jié)點(diǎn),而不要部署一個(gè)使用 32+GB 內(nèi)存的節(jié)點(diǎn)。

仍然要堅(jiān)持 50% 原則,假設(shè)你有個(gè)機(jī)器有 128G 內(nèi)存,你可以創(chuàng)建兩個(gè) Node,使用 32G 內(nèi)存。也就是說 64G 內(nèi)存給 ES 的堆內(nèi)存,剩下的 64G 給 Lucene。

服務(wù)器配置的選擇

Swapping 是性能的墳?zāi)梗涸谶x擇 ES 服務(wù)器時(shí),要盡可能地選擇與當(dāng)前應(yīng)用場(chǎng)景相匹配的服務(wù)器。

如果服務(wù)器配置很低,則意味著需要更多的節(jié)點(diǎn),節(jié)點(diǎn)數(shù)量的增加會(huì)導(dǎo)致集群管理的成本大幅度提高。

如果服務(wù)器配置很高,而在單機(jī)上運(yùn)行多個(gè)節(jié)點(diǎn)時(shí),也會(huì)增加邏輯的復(fù)雜度。

在計(jì)算機(jī)中運(yùn)行的程序均需在內(nèi)存執(zhí)行,若內(nèi)存消耗殆盡將導(dǎo)致程序無法進(jìn)行。為了解決這個(gè)問題,操作系統(tǒng)使用一種叫作虛擬內(nèi)存的技術(shù)。

當(dāng)內(nèi)存耗盡時(shí),操作系統(tǒng)就會(huì)自動(dòng)把內(nèi)存中暫時(shí)不使用的數(shù)據(jù)交換到硬盤中,需要使用的時(shí)候再?gòu)挠脖P交換到內(nèi)存。

如果內(nèi)存交換到磁盤上需要 10 毫秒,從磁盤交換到內(nèi)存需要 20 毫秒,那么多的操作時(shí)延累加起來,將導(dǎo)致幾何級(jí)增長(zhǎng)。

不難看出 Swapping 對(duì)于性能是多么可怕。所以為了使 ES 有更好等性能,強(qiáng)烈建議關(guān)閉 Swap。

關(guān)閉 Swap 的方式如下:

①暫時(shí)禁用。如果我們想要在 Linux 服務(wù)器上暫時(shí)關(guān)閉,可以執(zhí)行如下命令,但在服務(wù)器重啟后失效:

  1. sudo swapoff -a 

②關(guān)閉。我們可以修改 /etc/sysctl.conf(不同的操作系統(tǒng)路徑有可能不同),增加如下參數(shù):

  1. vm.swappiness = 1      //0-100,則表示越傾向于使用虛擬內(nèi)存。 

注意:Swappiness 設(shè)置為 1 比設(shè)置為 0 要好,因?yàn)樵谝恍﹥?nèi)核版本,Swappness=0 會(huì)引發(fā) OOM(內(nèi)存溢出)。

Swappiness 默認(rèn)值為 60,當(dāng)設(shè)置為 0 時(shí),在某些操作系統(tǒng)中有可能會(huì)觸發(fā)系統(tǒng)級(jí)的 OOM-killer,例如在 Linux 內(nèi)核的內(nèi)存不足時(shí),為了防止系統(tǒng)的崩潰,會(huì)自動(dòng)強(qiáng)制 Kill 一個(gè)“bad”進(jìn)程。

③在 ES 中設(shè)置。如果上面的方法都不能做到,你需要打開配置文件中的 mlockall 開關(guān),它的作用就是運(yùn)行 JVM 鎖住內(nèi)存,禁止 OS 交換出去。

在 elasticsearch.yml 配置如下:

  1. bootstrap.mlockall: true 

硬盤的選擇和設(shè)置

所以,如果條件允許,則請(qǐng)盡可能地使用 SSD,它的讀寫性能將遠(yuǎn)遠(yuǎn)超出任何旋轉(zhuǎn)介質(zhì)的硬盤(如機(jī)械硬盤、磁帶等)?;?SSD 的 ES 集群節(jié)點(diǎn)對(duì)于查詢和索引性能都有提升。

另外無論是使用固態(tài)硬盤還是使用機(jī)械硬盤,我們都建議將磁盤的陣列模式設(shè)置為 RAID 0,以此來提升磁盤的寫性能。

接入方式

ES 提供了 Transport Client(傳輸客戶端)和 Node Client(節(jié)點(diǎn)客戶端)的接入方式,這兩種方式各有利弊,分別對(duì)應(yīng)不同的應(yīng)用場(chǎng)景。

①Transport Client:作為一個(gè)集群和應(yīng)用程序之間的通信層,和集群是安全解耦的。

由于與集群解耦,所以在連接集群和銷毀連接時(shí)更加高效,適合大量的客戶端連接。

②Node Client:把應(yīng)用程序當(dāng)作一個(gè)集群中的 Client 節(jié)點(diǎn)(非 Data 和 Master 節(jié)點(diǎn))。

由于它是集群的一個(gè)內(nèi)部節(jié)點(diǎn),意味著它可以感知整個(gè)集群的狀態(tài)、所有節(jié)點(diǎn)的分布情況、分片的分布狀況等。

由于 Node Client 是集群的一部分,所以在接入和退出集群時(shí)進(jìn)行比較復(fù)雜操作,并且還會(huì)影響整個(gè)集群的狀態(tài),所以 Node Client 更適合少量客戶端,能夠提供更好的執(zhí)行效率。

角色隔離和腦裂

①角色隔離

ES 集群中的數(shù)據(jù)節(jié)點(diǎn)負(fù)責(zé)對(duì)數(shù)據(jù)進(jìn)行增、刪、改、查和聚合等操作,所以對(duì) CPU、內(nèi)存和 I/O 的消耗很大。

在搭建 ES 集群時(shí),我們應(yīng)該對(duì) ES 集群中的節(jié)點(diǎn)進(jìn)行角色劃分和隔離。

候選主節(jié)點(diǎn):

  1. node.master=true 
  2. node.data=false 

數(shù)據(jù)節(jié)點(diǎn):

  1. node.master=false 
  2. node.data=true 

形成如圖 3 所示的邏輯劃分:

圖 3

②避免腦裂

網(wǎng)絡(luò)異常可能會(huì)導(dǎo)致集群中節(jié)點(diǎn)劃分出多個(gè)區(qū)域,區(qū)域發(fā)現(xiàn)沒有 Master 節(jié)點(diǎn)的時(shí)候,會(huì)選舉出了自己區(qū)域內(nèi) Maste 節(jié)點(diǎn) r,導(dǎo)致一個(gè)集群被分裂為多個(gè)集群,使集群之間的數(shù)據(jù)無法同步,我們稱這種現(xiàn)象為腦裂。

為了防止腦裂,我們需要在 Master 節(jié)點(diǎn)的配置文件中添加如下參數(shù):

  1. discovery.zen.minimum_master_nodes=(master_eligible_nodes/2)+1        //默認(rèn)值為1 

其中 master_eligible_nodes 為 Master 集群中的節(jié)點(diǎn)數(shù)。這樣做可以避免腦裂的現(xiàn)象都出現(xiàn),提升集群的高可用性。

只要不少于 discovery.zen.minimum_master_nodes 個(gè)候選節(jié)點(diǎn)存活,選舉工作就可以順利進(jìn)行。

ES 實(shí)戰(zhàn)

ES 配置說明

在 ES 安裝目錄下的 Conf 文件夾中包含了一個(gè)重要的配置文件:elasticsearch.yaml。

ES 的配置信息有很多種,大部分配置都可以通過 elasticsearch.yaml 和接口的方式進(jìn)行。

下面我們列出一些比較重要的配置信息:

  • cluster.name:elasticsearch:配置 ES 的集群名稱,默認(rèn)值是 ES,建議改成與所存數(shù)據(jù)相關(guān)的名稱,ES 會(huì)自動(dòng)發(fā)現(xiàn)在同一網(wǎng)段下的集群名稱相同的節(jié)點(diǎn)。
  • node.nam: "node1":集群中的節(jié)點(diǎn)名,在同一個(gè)集群中不能重復(fù)。節(jié)點(diǎn)的名稱一旦設(shè)置,就不能再改變了。當(dāng)然,也可以設(shè)置成服務(wù)器的主機(jī)名稱,例如 node.name:${HOSTNAME}。
  • noed.master:true:指定該節(jié)點(diǎn)是否有資格被選舉成為 Master 節(jié)點(diǎn),默認(rèn)是 True,如果被設(shè)置為 True,則只是有資格成為 Master 節(jié)點(diǎn),具體能否成為 Master 節(jié)點(diǎn),需要通過選舉產(chǎn)生。
  • node.data:true:指定該節(jié)點(diǎn)是否存儲(chǔ)索引數(shù)據(jù),默認(rèn)為 True。數(shù)據(jù)的增、刪、改、查都是在 Data 節(jié)點(diǎn)完成的。
  • index.number_of_shards:5:設(shè)置都索引分片個(gè)數(shù),默認(rèn)是 5 片。也可以在創(chuàng)建索引時(shí)設(shè)置該值,具體設(shè)置為多大都值要根據(jù)數(shù)據(jù)量的大小來定。如果數(shù)據(jù)量不大,則設(shè)置成 1 時(shí)效率很高。
  • index.number_of_replicas:1:設(shè)置默認(rèn)的索引副本個(gè)數(shù),默認(rèn)為 1 個(gè)。副本數(shù)越多,集群的可用性越好,但是寫索引時(shí)需要同步的數(shù)據(jù)越多。
  • path.conf:/path/to/conf:設(shè)置配置文件的存儲(chǔ)路徑,默認(rèn)是 ES 目錄下的 Conf 文件夾。建議使用默認(rèn)值。
  • path.data:/path/to/data1,/path/to/data2:設(shè)置索引數(shù)據(jù)多存儲(chǔ)路徑,默認(rèn)是 ES 根目錄下的 Data 文件夾。切記不要使用默認(rèn)值,因?yàn)槿?ES 進(jìn)行了升級(jí),則有可能數(shù)據(jù)全部丟失。

可以用半角逗號(hào)隔開設(shè)置的多個(gè)存儲(chǔ)路徑,在多硬盤的服務(wù)器上設(shè)置多個(gè)存儲(chǔ)路徑是很有必要的。

  • path.logs:/path/to/logs:設(shè)置日志文件的存儲(chǔ)路徑,默認(rèn)是 ES 根目錄下的 Logs,建議修改到其他地方。
  • path.plugins:/path/to/plugins:設(shè)置第三方插件的存放路徑,默認(rèn)是 ES 根目錄下的 Plugins 文件夾。
  • bootstrap.mlockall:true:設(shè)置為 True 時(shí)可鎖住內(nèi)存。因?yàn)楫?dāng) JVM 開始 Swap 時(shí),ES 的效率會(huì)降低,所以要保證它不 Swap。
  • network.bind_host:192.168.0.1:設(shè)置本節(jié)點(diǎn)綁定的 IP 地址,IP 地址類型是 IPv4 或 IPv6,默認(rèn)為 0.0.0.0。
  • network.publish_host:192.168.0.1:設(shè)置其他節(jié)點(diǎn)和該節(jié)點(diǎn)交互的 IP 地址,如果不設(shè)置,則會(huì)進(jìn)行自我判斷。
  • network.host:192.168.0.1:用于同時(shí)設(shè)置 bind_host 和 publish_host 這兩個(gè)參數(shù)。
  • http.port:9200:設(shè)置對(duì)外服務(wù)的 HTTP 端口,默認(rèn)為 9200。ES 的節(jié)點(diǎn)需要配置兩個(gè)端口號(hào),一個(gè)對(duì)外提供服務(wù)的端口號(hào),一個(gè)是集群內(nèi)部使用的端口號(hào)。
  • http.port 設(shè)置的是對(duì)外提供服務(wù)的端口號(hào)。注意,如果在一個(gè)服務(wù)器上配置多個(gè)節(jié)點(diǎn),則切記對(duì)端口號(hào)進(jìn)行區(qū)分。
  • transport.tcp.port:9300:設(shè)置集群內(nèi)部的節(jié)點(diǎn)間交互的 TCP 端口,默認(rèn)是 9300。注意,如果在一個(gè)服務(wù)器配置多個(gè)節(jié)點(diǎn),則切記對(duì)端口號(hào)進(jìn)行區(qū)分。
  • transport.tcp.compress:true:設(shè)置在節(jié)點(diǎn)間傳輸數(shù)據(jù)時(shí)是否壓縮,默認(rèn)為 False,不壓縮。
  • discovery.zen.minimum_master_nodes:1:設(shè)置在選舉 Master 節(jié)點(diǎn)時(shí)需要參與的最少的候選主節(jié)點(diǎn)數(shù),默認(rèn)為 1。如果使用默認(rèn)值,則當(dāng)網(wǎng)絡(luò)不穩(wěn)定時(shí)有可能會(huì)出現(xiàn)腦裂。

合理的數(shù)值為(master_eligible_nodes/2)+1,其中 master_eligible_nodes 表示集群中的候選主節(jié)點(diǎn)數(shù)。

  • discovery.zen.ping.timeout:3s:設(shè)置在集群中自動(dòng)發(fā)現(xiàn)其他節(jié)點(diǎn)時(shí) Ping 連接的超時(shí)時(shí)間,默認(rèn)為 3 秒。

在較差的網(wǎng)絡(luò)環(huán)境下需要設(shè)置得大一點(diǎn),防止因誤判該節(jié)點(diǎn)的存活狀態(tài)而導(dǎo)致分片的轉(zhuǎn)移。

常用接口

雖然現(xiàn)在有很多開源軟件對(duì) ES 的接口進(jìn)行了封裝,使我們可以很方便、直觀地監(jiān)控集群的狀況,但是在 ES 5 以后,很多軟件開始收費(fèi)。

了解常用的接口有助于我們?cè)诔绦蚧蛘吣_本中查看我們的集群情況,以下接口適用于 ES 6.5.2 版本。

①索引類接口

通過下面的接口創(chuàng)建一個(gè)索引名稱為 indexname 且包含 3 個(gè)分片、1 個(gè)副本的索引:

  1. PUT http://localhost:9200/indexname?pretty 
  2. content-type →application/json; charset=UTF-8 
  3.     "settings":{ 
  4.         "number_of_shards" : 3, 
  5.         "number_of_replicas" : 1 
  6.     } 

通過下面都接口刪除索引:

  1. DELETE http://localhost:9200/indexname 

通過該接口就可以刪除索引名稱為 indexname 的索引,通過下面的接口可以刪除多個(gè)索引:

  1. DELETE http://localhost:9200/indexname1,indexname2 
  2. DELETE http://localhost:9200/indexname* 

通過下面的接口可以刪除集群下的全部索引:

  1. DELETE http://localhost:9200/_all 
  2. DELETE http://localhost:9200/* 

進(jìn)行全部索引刪除是很危險(xiǎn)的,我們可以通過在配置文件中添加下面的配置信息,來關(guān)閉使用 _all 和使用通配符刪除索引的接口,使用刪除索引職能通過索引的全稱進(jìn)行。

  1. action.destructive_requires_name: true 

通過下面的接口獲取索引的信息,其中,Pretty 參數(shù)用語(yǔ)格式化輸出結(jié)構(gòu),以便更容易閱讀:

  1. GET http://localhost:9200/indexname?pretty 

通過下面的接口關(guān)閉、打開索引:

  1. POST http://localhost:9200/indexname/_close 
  2. POST http://localhost:9200/indexname/_open 

通過下面的接口獲取一個(gè)索引中具體 Type 的 Mapping 映射:

  1. GET http://localhost:9200/indexname/typename/_mapping?pretty 

當(dāng)一個(gè)索引中有多個(gè) Type 時(shí),獲得 Mapping 時(shí)要加上 Typename。

②Document 操作

安裝 ES 和 Kibana 之后,進(jìn)入 Kibana 操作頁(yè)面,然后進(jìn)去的 DevTools 執(zhí)行下面操作:

  1. #添加一條document 
  2. PUT /test_index/test_type/1 
  3.     "test_content":"test test" 
  4. #查詢 
  5. GET /test_index/test_type/1 
  6. #返回 
  7.   "_index" : "test_index"
  8.   "_type" : "test_type"
  9.   "_id" : "1"
  10.   "_version" : 2, 
  11.   "found" : true
  12.   "_source" : { 
  13.     "test_content" : "test test" 
  14.   } 

put/index/type/id 說明如下:

  • _index 元數(shù)據(jù):代表這個(gè) Document 存放在哪個(gè) Idnex 中,類似的數(shù)據(jù)放在一個(gè)索引,非類似的數(shù)據(jù)放不同索引,Index 中包含了很多類似的 Document。
  • _type 元數(shù)據(jù):代表 Document 屬于 Index 中的哪個(gè)類別(type),一個(gè)索引通常會(huì)劃分多個(gè) Type,邏輯上對(duì) Index 中有些許不同的幾類數(shù)據(jù)進(jìn)行分類。
  • _id 元數(shù)據(jù):代表 Document 的標(biāo)識(shí),id 與 Index 和 Type 一起,可以標(biāo)識(shí)和定位一個(gè) Document,可以理解為數(shù)據(jù)庫(kù)中主鍵。我們可以指定 Document 的 id,也可以不指定,由ES自動(dòng)為我們創(chuàng)建一個(gè) id。

接口應(yīng)用

①Search 接口

Search 是我們最常用的 API,ES 給我提供了豐富的查詢條件,比如模糊匹配 Match,字段判空 Exists,精準(zhǔn)匹配 Term 和 Terms,范圍匹配 Range:

  1. GET /_search 
  2.   "query": {  
  3.     "bool": {  
  4.       "must": [     //must_not 
  5.         { "match": { "title":   "Search"        }},  
  6.         { "match": { "content""Elasticsearch" }}, 
  7.         {"exists":{"field":"字段名"}}   //判斷字段是否為空 
  8.       ], 
  9.       "filter": [  
  10.         { "term":  { "status""published" }}, 
  11.         { "terms":  { "status": [0,1,2,3] }},//范圍 
  12.         { "range": { "publish_date": { "gte""2015-01-01" }}} //范圍gte:大于等于;gt:大于;lte:小于等于;lt:小于 
  13.       ] 
  14.     } 
  15.   } 

查詢索引為 test_index,doc 類型為 test_type 的數(shù)據(jù):

  1. GET /test_index/test_type/_search 

查詢索引為 test_index,doc 類型為 test_type,docment 字段 num10 為 4 的數(shù)據(jù):

  1. GET /test_index/test_type/_search?pretty=true 
  2.   "query": {  
  3.     "bool": {  
  4.       "filter": [  
  5.         { "term":  { "num10": 4 }} 
  6.       ] 
  7.     } 
  8.   } 

更多查詢條件的組合,大家可以自行測(cè)試。

②修改 Mapping

  1. PUT /my_index/_mapping/my_type 
  2.   "properties": { 
  3.        "new_field_name": { 
  4.            "type":     "string"         //字段類型,string、long、boolean、ip 
  5.        } 
  6.    } 

如上是修改 Mapping 結(jié)構(gòu),然后利用腳本 Script 給字段賦值:

  1. POST my_index/_update_by_query 
  2.   "script": { 
  3.     "lang""painless"
  4.     "inline""ctx._source.new_field_name= '02'" 
  5.   } 

③修改別名

如下給 Index 為 test_index 的數(shù)據(jù)綁定 Alias 為 test_alias:

  1. POST /_aliases 
  2.   "actions": [ 
  3.     { 
  4.       "add": {      //add,remove 
  5.         "index""test_index"
  6.         "alias""test_alias" 
  7.       } 
  8.     } 
  9.   ] 

驗(yàn)證別名關(guān)聯(lián),根據(jù)別名來進(jìn)行數(shù)據(jù)查詢,如下:

  1. GET /test_alias/test_type/3 

④定制返回內(nèi)容

_source 元數(shù)據(jù):就是說,我們?cè)趧?chuàng)建一個(gè) Document 的時(shí)候,使用的那個(gè)放在 Request Body 中的 Json 串(所有的 Field),默認(rèn)情況下,在 Get 的時(shí)候,會(huì)原封不動(dòng)的給我們返回回來。

定制返回的結(jié)果,指定 _source 中,返回哪些 Field:

  1. #語(yǔ)法: 
  2. GET /test_index/test_type/1?_source=test_field2 
  3. #返回 
  4.   "_index" : "test_index"
  5.   "_type" : "test_type"
  6.   "_id" : "1"
  7.   "_version" : 3, 
  8.   "found" : true
  9.   "_source" : { 
  10.     "test_field2" : "test field2" 
  11.   } 
  12. #也可返回多個(gè)field使用都好分割 
  13. GET /test_index/test_type/1?_source=test_field2,test_field1 

Java 封裝

組件 elasticsearch.jar 提供了豐富 API,不過不利于我們理解和學(xué)習(xí),現(xiàn)在我們自己來進(jìn)行封裝。

組件 API 使用 RestClient 封裝 Document 查詢接口:

  1. /** 
  2.  * @param index 
  3.  * @param type 
  4.  * @param id 
  5.  * @param fields 
  6.  *            查詢返回字段,可空 
  7.  * @return 
  8.  * @throws Exception 
  9.  * @Description: 
  10.  * @create date 2019年4月3日下午3:12:40 
  11.  */ 
  12. public String document(String index, String type, String id, List<String> fields) throws Exception { 
  13.     Map<String, String> paramsMap = new HashMap<>(); 
  14.     paramsMap.put("pretty""true"); 
  15.     if (null != fields && fields.size() != 0) { 
  16.         String fieldValue = ""
  17.         for (String field : fields) { 
  18.             fieldValue += field + ","
  19.         } 
  20.         if (!"".equals(fieldValue)) { 
  21.             paramsMap.put("_source", fieldValue); 
  22.         } 
  23.     } 
  24.     return CommonUtils.toString(es.getRestClient() 
  25.             .performRequest("GET""/" + index + "/" + type + "/" + id, paramsMap).getEntity().getContent()); 

工程使用,封裝:

  1. public String searchDocument(String index, String type, String id, List<String> fields) { 
  2.     try { 
  3.         return doc.document(index, type, id, fields); 
  4.     } catch (Exception e) { 
  5.         log.error(e.getMessage()); 
  6.         ExceptionLogger.log(e); 
  7.         throw new RuntimeException("ES查詢失敗"); 
  8.     } 

測(cè)試用例,代碼如下:

  1. /** 
  2.  * ES交互驗(yàn)證-查詢、更新等等操作 
  3.  * 
  4.  * @version 
  5.  * @author 錢丁君-chandler 2019年4月3日上午10:27:28 
  6.  * @since 1.8 
  7.  */ 
  8. @RunWith(SpringRunner.class) 
  9. @SpringBootTest(classes = Bootstrap.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
  10. public class ESManagerTest { 
  11.     @Autowired 
  12.     private ESBasicManager esBasicManager; 
  13.     @Test 
  14.     public void query() { 
  15.         String result = esBasicManager.searchDocument(ESTagMetadata.INDEX_ALIAS, ESTagMetadata.DOC_TYPE, 
  16.                 "188787665220752824", ImmutableList.of("signup_time""tag_days_no_visit_after_1_order")); 
  17.         System.out.println("----------->" + result); 
  18.     } 

控臺(tái)輸出:

  1. ----------->{ 
  2.   "_index" : "crm_tag_idx_20181218_708672"
  3.   "_type" : "crm_tag_type"
  4.   "_id" : "188787665220752824"
  5.   "_version" : 1, 
  6.   "found" : true
  7.   "_source" : { 
  8.     "signup_time" : "2017-12-24"
  9.     "tag_days_no_visit_after_1_order" : "339" 
  10.   } 

我只是拋磚引玉,大家可以自行進(jìn)行各種操作的封裝,不管對(duì)于理解 ES 的使用,還是對(duì)代碼質(zhì)量提升都有很多幫助。

作者:錢丁君

簡(jiǎn)介:就職于永輝云創(chuàng),擔(dān)任基礎(chǔ)架構(gòu)開發(fā),有多年基礎(chǔ)架構(gòu)經(jīng)驗(yàn),主要從事電商新零售、互聯(lián)網(wǎng)金融行業(yè)。技術(shù)發(fā)燒友,涉獵廣泛。熟悉 Java 微服務(wù)架構(gòu)搭建、推進(jìn)、衍化;多種中間件搭建、封裝和優(yōu)化;自動(dòng)化測(cè)試開發(fā)、代碼規(guī)約插件開發(fā)、代碼規(guī)范推進(jìn);容器化技術(shù) Docker、容器化編排技術(shù) Kubernetes,有較為豐富的運(yùn)維經(jīng)驗(yàn)。

【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】

 

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2019-01-15 09:34:30

MySQL高性能優(yōu)化

2014-03-19 14:34:06

JQuery高性能

2024-03-07 11:03:21

ElasticseaES索引

2021-08-13 09:06:52

Go高性能優(yōu)化

2020-07-16 08:06:53

網(wǎng)關(guān)高性能計(jì)

2019-03-01 11:03:22

Lustre高性能計(jì)算

2022-08-15 08:01:35

微服務(wù)框架RPC

2020-03-23 15:15:57

MySQL性能優(yōu)化數(shù)據(jù)庫(kù)

2018-01-12 14:37:34

Java代碼實(shí)踐

2023-07-28 08:23:05

選擇器Java NIO

2024-11-20 19:56:36

2011-07-21 13:51:38

java

2011-07-21 14:15:08

java

2009-01-05 10:00:11

JSP優(yōu)化Servlet性能優(yōu)化

2023-08-29 15:10:04

持續(xù)性能優(yōu)化開發(fā)

2020-07-17 19:55:50

Vue前端性能優(yōu)化

2010-07-06 09:07:09

2018-03-30 18:17:10

MySQLLinux

2019-04-02 10:36:17

數(shù)據(jù)庫(kù)MySQL優(yōu)化方法

2018-09-18 17:20:14

MySQL優(yōu)化數(shù)據(jù)庫(kù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)