Elastic Stack-Elasticsearch使用介紹(五)
一、前言
前4篇將Elasticsearch用法的API和原理方面東西介紹了一下,相信大家對Elasticsearch有了一定的認知,接下我們主要從索引的建立到後期的一些優化做一些介紹;
二、Mapping構建
之前介紹過Index就如同我們的資料庫database,type相當於我們的表,而Mapping就是構建這些欄位和索引關係的橋樑。資料庫構建的時候我們要遵守三正規化,那Mapping構建的時候我們要考慮那些因素?我認為要有以下幾方面的考慮:
1.欄位是什麼型別;
對欄位的型別做過介紹,考慮這個時候和資料庫欄位設定考慮問題基本一樣;
2.是否需要被檢索,也就是是否需要分詞;
不需要檢索的欄位:index設定為false;不需要檢索的字元型別直接設定成keyword型別;
需要檢索的欄位,可以通過index_options設定需要的儲存分詞的粒度,主要有以下四種引數docs 、 freqs 、 position 、 offsets,根據需要自行設定;
3.是否需要排序和聚合;
不需要排序或者聚合分析功能:doc_values設定為 false,fielddata設定為 false;
如果一個欄位不需要檢索、排序、聚合分析,則enabled設定為false;
4.是否需要另外的儲存;
通過store 設定 true,即可儲存該欄位的原始內容,這裡這個舉個例子
以上就是我們建立Mapping時候需要考慮一些東西,接下來我們還有另外一個問題,資料庫中表與表之間是有關聯關係的,這個在Elasticsearch中是如何體現的?
在Elasticsearch中有兩種方式可以去實現關聯關係,
1.Nested Object(巢狀物件)
舉個例子:
這個時候user欄位會被對映成為object型別,這個時候JSON文件會被處理成為:
當我們查詢的時候,就會意外出現的結果;
結果:
Elasticsearch針對這種情況提供Nested Object(巢狀物件)這個解決方案,
增加這一個步驟然後再按照上面步驟操作,就得到我們想要的結果;
當使用Nested Object內部是使用巢狀文件,當搜尋first name為Alice和last name為White的時候就查詢不到;
2.join
join資料型別是在同一個索引通過Parent和Child去指定父文件和子文件,然後形成1對多或者1對1的關係,舉個例子:
我這個是5.0以上的版本,不是6.0的版本,這個我還是忘記說,大家注意下版本問題,我大概說下這個意思就是隻指定my_join_field欄位question的父級為answer;
接下來我們再加入2條父級文件:
接下來在加入2條子文件:
這裡需要注意的問題是路由必須要指定,父級文件必須和自己文件在同一個分片上,另外就是指定join的文件和父id;
這個時候我們檢視下我們形成的文件:
{ "took": 13, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": null, "hits": [ { "_index": "my_index", "_type": "doc", "_id": "1", "_score": null, "_source": { "text": "This is a question", "my_join_field": { "name": "question" } }, "sort": [ "1" ] }, { "_index": "my_index", "_type": "doc", "_id": "2", "_score": null, "_source": { "text": "This is a another question", "my_join_field": { "name": "question" } }, "sort": [ "2" ] }, { "_index": "my_index", "_type": "doc", "_id": "3", "_score": null, "_routing": "1", "_source": { "text": "This is an answer", "my_join_field": { "name": "answer", "parent": "1" } }, "sort": [ "3" ] }, { "_index": "my_index", "_type": "doc", "_id": "4", "_score": null, "_routing": "1", "_source": { "text": "This is another answer", "my_join_field": { "name": "answer", "parent": "1" } }, "sort": [ "4" ] } ] } } View Code
看到結果我們就可以知道我們的1對多關係已經建立起來了,接下來我們按照父id來查詢父id為1的文件:
這個地方還要提醒下,也是可以使用get的,只是使用神器的時候這樣比較方便;
結果如下:
還可以使用has_child 返回包含某子文件的父文件,has_parent 返回包含某父文件的子文件這些就不寫例子自己探索一下吧;
接下來做個對比:
注意:Mapping欄位不要設定太多;
三、部分優化的意見
elasticsearch.yml中建議設定的引數:
之前叢集搭建的時候大家肯定設定一些引數,另外上面你的介紹也設定了一些引數,我們也具體來說下在上生產環境之前到底要設定那些引數:
1.cluster.name叢集名稱;
2.node.name節點名稱;
3.node.master是否是主節點;
4.node.data是否存放資料,主節點不建議存放資料;
5.discovery.zen.ping.unicast.hosts設定叢集的其他節點;
6.network.host IP;
7.path.data and path.logs 存放記錄和日誌的目錄,預設是在Elasticsearch目錄下;
8.discovery.zen.minimum_master_nodes 叢集掛掉以後選舉主的個數;
JVM設定:
1.將最小堆大小(Xms)和最大堆大小(Xmx)設定為彼此相等,防止垃圾回收過於頻繁;
2.將Xmx設定為不超過物理RAM的50%,以確保有足夠的物理RAM用於核心檔案系統快取;
3.不要超過32GB,這是JVM優化的建議;
分片的設定:
建議閱讀這篇 ofollow,noindex" target="_blank">文章 ;
讀寫優化:
寫入的優化,這個參考下 Elastic Stack-Elasticsearch使用介紹(三)這篇文章 ,這篇文章我介紹寫入時候的一些步驟,我們優化的方向就是從這3個方向:
當然要貫徹多執行緒、批量寫入這個不能變得方針,針對refresh、translog、flush這3個方面做優化:
1.refresh
每refresh一次都會生成一個segment,如果refresh頻率過高,可能會照成segment包含的文件數是很少,生成很多的segment;
調整方向
增大refresh_interval,降低實時性,預設是1s,設定為-1直接禁止自動refresh;
增大快取區的大小,引數為indices.memory.index_buffer_size(靜態引數,在elasticsearch.yml中設定,該引數設定後必須重啟節點),預設為10%;
2.translog
目標是降低translog寫磁碟的頻率,從而提高效率,但是這樣就會有掉丟資料的風險;
調整方向
index.translog.durabiliy設定為asyn,index.translog.sync_interval設定寫入時間的間隔,單位是秒,比如10s,那麼translog會改為每10s寫一次磁碟,這個時候如果宕機就會丟失資料;
index.translog.flush_threshold_size 預設為512MB,超過該大小時會觸發一次flush;
3.合理設定節點和分片的個數,通過設定index.routing.allocation.total_shards_per_node 限定每個索引在每個節點上可分配的總主副分片的個數;
讀取的優化:
1.合理設定分片數
通過測試一個分片效能,然後根據業務進行計算,設定合理的分片個數;怎麼測試一個分片的效能?首先搭建與生產一樣的環境,接下來設定一個單分片無副本的索引,然後進行寫入資料測試 和查詢資料,然後根據提供的監控指標進行監控壓力測試的情況,這部分監控內容下一章進行講解;壓測工具可以使用esrally,參考下這篇 文章 ;
2.優化查詢語句
儘量使用Filter上下文,減少算分的場景,由於Filter有快取機制,可以提升查詢效能;
四、結束
接下來會開始說一說監控的問題,歡迎大家加群438836709,歡迎大家關注我公眾號!